Hi,

Another option is to use fixtures to obtain the values, since fixtures can
be overwritten in subclasses:

import pytest
class Base:

    @pytest.fixture(scope='class')
    def param(self):
        assert 0

    @pytest.yield_fixture(scope='class')
    def fix(self, param, request):
        print 'setup:', request.cls, param
        yield
        print 'teardown:', request.cls, param
class TestA(Base):

    @pytest.fixture(scope='class')
    def param(self):
        return 'value from A'

    def test_1(self, fix):
        pass

    def test_2(self, fix):
        pass
class TestB(Base):

    @pytest.fixture(scope='class')
    def param(self):
        return 'value from B'

    def test_3(self, fix):
        pass

    def test_4(self, fix):
        pass

This yields the expected results:

foo.py::TestA::test_1 setup: foo.TestA value from A
PASSED
foo.py::TestA::test_2 PASSEDteardown: foo.TestA value from A

foo.py::TestB::test_3 setup: foo.TestB value from B
PASSED
foo.py::TestB::test_4 PASSEDteardown: foo.TestB value from B

If your parameters to the fixtures are simple values (like in my example),
I would go with Holger’s suggestion of using simple class attributes.

Fixtures might be useful thought if you are returning more complex objects,
because then you have the full power of the fixtures machinery to access
other fixtures if needed. For example, one of the subclasses might need a
temporary directory to create a file in.

As a more detailed example, suppose you plan to test several data
serializers, like json and pickle. Most of the tests are nearly the same,
create a python data structure, dump, load and compare. One approach is to
put the tests in a base class, and have subclasses with fixtures that
provide a serializer instance for their tests:

class BaseSerializerTests:

    def test_dict(self, serializer):
        d = {'x': 1, 'y': 2}
        stream = serializer.dumps(d)
        d2 = serializer.loads(stream)
        assert d == d2
class TestPickle(BaseSerializerTests):

    @pytest.fixture
    def serializer(self):
        return pickle.PicklerCodec()
class TestJSON(BaseSerializerTests):

    @pytest.fixture
    def serializer(self):
        return json.JSONCodec()

Cheers,
​

On Tue, Dec 15, 2015 at 8:17 AM holger krekel <hol...@merlinux.eu> wrote:

> Hi Alex,
>
> On Tue, Dec 15, 2015 at 09:18 +0000, Alex Netes wrote:
> > Hi holger,
> >
> > Thanks for your help.
> >
> > > Hi Alex,
> > >
> > > On Mon, Dec 14, 2015 at 15:50 +0000, Alex Netes wrote:
> > >> Hello guys,
> > >>
> > >> I'm new to Pytest and I encounter something I cannot explain.
> > >
> > > I also hit many things which i can not explain, even with pytest and
> maybe even with this very mail.
> > >
> >
> > I'll try to explain my intention in behind my code, instead of showing
> my nitty code.
> >
> > >> I'm trying to give fixture fixt_func() a parameter fixt_prm and
> expect the fixture to be called only
> > >> once as it defined with 'class' scope, but the fixture is called
> twice as it ignores the scope. What am I
> > >> missing?
> > >>
> > >>
> > >> @pytest.fixture(scope='class')
> > >> def fixt_func(request, resource, fixt_prm):
> > >>     print fixt_prm
> > >>
> > >> class TestA():
> > >>     @pytest.mark.parametrize('resource', ['x'], scope='class')
> > >>     @pytest.mark.parametrize(fixt_prm ', ['x'], scope='class')
> > >>     @pytest.mark.parametrize('prm', ['a', 'b'])
> > >>     def test_a(self, prm, fixt_func)
> > >>         assert True
> > >
> > > You are doing something i wasn't aware is possible. You pass a
> parameter to the fixture function
> > > fixt_func through parametrization but as a fixture.
> > > In any case, if we modify your example to:
> > >
> > >     import pytest
> > >     @pytest.fixture(scope='class')
> > >     def fixt_func(request, fixt_prm):
> > >         print "fixt_func"
> > >
> > >     class TestA():
> > >         @pytest.mark.parametrize('fixt_prm', ['x', 'y'], scope='class')
> > >         def test_a(self, fixt_func):
> > >             assert True
> > >
> > > this will also call fixt_func twice for the two executing tests.
> > > It's argubaly "correct" behaviour from a certain point of view.
> > > fixt_prm is class-scoped so each parameter instance exists as a
> different "class-level" value so we
> > > interpret it to mean each class-scoped fixture function needs to be
> executed with both values.
> > >
> > > Just imagine we wouldn't parametrize on the function directly but
> through a fixture function:
> > >
> > >     import pytest
> > >     @pytest.fixture(scope='class')
> > >     def fixt_func(request, fixt_prm):
> > >         print "fixt_func"
> > >
> > >     @pytest.fixture(scope='class', params=["x", "y"])
> > >     def fixt_prm(request):
> > >         print "fixt_prm"
> > >
> > >     class TestA():
> > >         def test_a(self, fixt_func):
> > >             assert True
> > >
> > > Here it's maybe more obvious why this executes both fixture functions
> twice.
> > >
> > > however, i am not sure about your precise example above.  I can see
> why you expect the two
> > > different "prm" values (and thus test functions) to execute with the
> same class-level fixtures.  Maybe
> > > others can chime in and say if they consider your example a bug or a
> "usual" behaviour.
> > >
> >
> > Your examples makes sense. I'm trying to do something more complex and
> maybe I look at it in a wrong
> > way. I want to define a fixture "fixt_func" so it would be able to
> receive a parameter defined by different
> > test classes. Moreover I want "fixt_func" to have Class scope, so I can
> call finalize when all tests of the
> > same class finished running. That's why I came up with the above
> "solution".
>
> I think you could use a marker on the class or even just a class attribute:
>
>     import pytest
>
>     @pytest.fixture(scope="class")
>     def fix(request):
>         return request.cls.attr * 10
>
>     class TestA:
>         attr = 1
>
>         def test_one(self, fix):
>             assert 0
>
>     class TestB:
>         attr = 2
>
>         def test_one(self, fix):
>             assert 0
>
> The "request" object gives you back references into the context
> of the test which requests fixtures.
>
> HTH,
> holger
> _______________________________________________
> pytest-dev mailing list
> pytest-dev@python.org
> https://mail.python.org/mailman/listinfo/pytest-dev
>
_______________________________________________
pytest-dev mailing list
pytest-dev@python.org
https://mail.python.org/mailman/listinfo/pytest-dev

Reply via email to