Hello guys, I'm new to Pytest and I encounter something I cannot explain. 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
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'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. holger
_______________________________________________ pytest-dev mailing list pytest-dev@python.org https://mail.python.org/mailman/listinfo/pytest-dev
-- about me: http://holgerkrekel.net/about-me/ contracting: http://merlinux.eu
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".
holger
_______________________________________________ pytest-dev mailing list pytest-dev@python.org https://mail.python.org/mailman/listinfo/pytest-dev
-- about me: http://holgerkrekel.net/about-me/ contracting: http://merlinux.eu
************************************************************************************ This footnote confirms that this email message has been scanned by PineApp Mail-SeCure for the presence of malicious code, vandals & computer viruses. ************************************************************************************
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
Hi holger,
Hi Alex,
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
On Tue, Dec 15, 2015 at 09:18 +0000, Alex Netes wrote: 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.
Thanks. I think marker option better suite my needs. However, I have two questions. 1. I hit a problem with getting marker parameter from the fixture when it defined with 'class' scope. When I remove the scope, it works. Import pytest @pytest.fixture(scope="class") def fix(request): print request.node.get_marker('attr') # None @pytest.mark.attr('something') class TestA: def test_one(self, fix): assert 0 ------------------------------ Import pytest @pytest.fixture def fix(request): print request.node.get_marker('attr') # <MarkInfo 'attr' args=('something',) kwargs={}> @pytest.mark.attr('something') class TestA: def test_one(self, fix): assert 0 2. Is it possible to provide arguments to the marker via the command line?
On Tue, Dec 15, 2015 at 14:11 +0000, Alex Netes wrote:
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.
Thanks. I think marker option better suite my needs. However, I have two questions. 1. I hit a problem with getting marker parameter from the fixture when it defined with 'class' scope. When I remove the scope, it works.
Import pytest
@pytest.fixture(scope="class") def fix(request): print request.node.get_marker('attr') # None
@pytest.mark.attr('something') class TestA: def test_one(self, fix): assert 0
I don't think there is much point in using a marker. IISIC the missing marker on class-level is something that should work.
------------------------------ Import pytest
@pytest.fixture def fix(request): print request.node.get_marker('attr') # <MarkInfo 'attr' args=('something',) kwargs={}>
@pytest.mark.attr('something') class TestA: def test_one(self, fix): assert 0
2. Is it possible to provide arguments to the marker via the command line?
You can receive options via request.config.getoption(...) from a fixture function. You can not easily access command line options when applying a marker because that happens at import time when options might not be available yet. In some cases it might work to use ``pytest.config.getoption()`` within a marker however. holger
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 <holger@merlinux.eu> wrote:
Hi Alex,
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
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
On Tue, Dec 15, 2015 at 09:18 +0000, Alex Netes wrote: parameter to the fixture function 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
participants (3)
-
Alex Netes -
Bruno Oliveira -
holger krekel