Running finalizer in case test setup has failed
Hello All, We have complex enough (several stages of putting the test environment into some condition) code which should be executed in all cases regardless of test setup result (fixture setup). Since finalizer for fixture will not be called in case its (fixture) setup failed we've put some calls to pytest_sessionfinish as a temporary workaround but we need to find a way how to call finalizer code explicitly. Could you please suggest how to achieve that? Thank you in advance! -Andrii
Hi Andrii, On Mon, Nov 11, 2013 at 19:56 +0200, Andrii Smirnov wrote:
Hello All,
We have complex enough (several stages of putting the test environment into some condition) code which should be executed in all cases regardless of test setup result (fixture setup).
Since finalizer for fixture will not be called in case its (fixture) setup failed we've put some calls to pytest_sessionfinish as a temporary workaround but we need to find a way how to call finalizer code explicitly.
Calling fixture finalizers from such a hook is hard if even possible. But i don't understand yet why your finalizers are not run. Take this example:: import pytest @pytest.fixture def fix(request): def fin(): print "finalizing!" request.addfinalizer(fin) 0/0 def test_hello(fix): pass If you run this with ``py.test -s`` you will see the ``finalizing!`` message although the fixture function fails. If you are running xUnit-style ``setup*`` functions then indeed, pytest is compatible to the way unittest or nose do xUnit setup: teardownX functions are not run if a setupX function fails. However, you can transform any such setup function into a pytest style one by puttig a fixture-autouse decorator in front:: @pytest.fixture(autouse=True) def setup_function(request): # as above you can register finalizers etc. If you use the decorator you can also use other pytest fixtures such as ``tmpdir`` or ``monkeypatch`` or your own fixtures, of course. If both examples don't answer your question, please try to give a code example on how things fail for you. cheers, holger
Also as I found that addfinalizer is more robust approach in comparison with yield_fixture. If we get an exception before yield statement anything after it won't be executed: import pytest @pytest.yield_fixture def yfix(request): def fin(): print "finalizing!" 0/0 yield fin() def test_hello(yfix): pass $ py.test -s test_finalizing.py ============================ test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.4.2 plugins: cov collected 1 items test_finalizing.py E ================================== ERRORS =================================== _______________________ ERROR at setup of test_hello ________________________ request = <FixtureRequest for <Function 'test_hello'>> @pytest.yield_fixture def yfix(request): def fin(): print "finalizing!"
0/0
E ZeroDivisionError: integer division or modulo by zero test_finalizing.py:15: ZeroDivisionError ========================== 1 error in 0.01 seconds ========================== Best regards, Anton On Tue, Nov 12, 2013 at 11:16 AM, holger krekel <holger@merlinux.eu> wrote:
Hi Andrii,
On Mon, Nov 11, 2013 at 19:56 +0200, Andrii Smirnov wrote:
Hello All,
We have complex enough (several stages of putting the test environment into some condition) code which should be executed in all cases regardless of test setup result (fixture setup).
Since finalizer for fixture will not be called in case its (fixture) setup failed we've put some calls to pytest_sessionfinish as a temporary workaround but we need to find a way how to call finalizer code explicitly.
Calling fixture finalizers from such a hook is hard if even possible.
But i don't understand yet why your finalizers are not run. Take this example::
import pytest
@pytest.fixture def fix(request): def fin(): print "finalizing!"
request.addfinalizer(fin) 0/0
def test_hello(fix): pass
If you run this with ``py.test -s`` you will see the ``finalizing!`` message although the fixture function fails.
If you are running xUnit-style ``setup*`` functions then indeed, pytest is compatible to the way unittest or nose do xUnit setup: teardownX functions are not run if a setupX function fails. However, you can transform any such setup function into a pytest style one by puttig a fixture-autouse decorator in front::
@pytest.fixture(autouse=True) def setup_function(request): # as above you can register finalizers etc.
If you use the decorator you can also use other pytest fixtures such as ``tmpdir`` or ``monkeypatch`` or your own fixtures, of course.
If both examples don't answer your question, please try to give a code example on how things fail for you.
cheers, holger _______________________________________________ Pytest-dev mailing list Pytest-dev@python.org https://mail.python.org/mailman/listinfo/pytest-dev
On Wed, Nov 20, 2013 at 18:26 +0200, Anton P wrote:
Also as I found that addfinalizer is more robust approach in comparison with yield_fixture. If we get an exception before yield statement anything after it won't be executed:
import pytest
@pytest.yield_fixture def yfix(request): def fin(): print "finalizing!" 0/0 yield fin()
def test_hello(yfix): pass
Sure, your example should better read: @pytest.yield_fixture def yfix(request): 0/0 yield print "finalizing!" and then it's clear that the print statement is not executed. This is strictly equivalent to: @pytest.fixture def yfix(request): 0 / 0 def fin(): print "finalizing!" request.addfinalizer(fin) return None It really only makes a difference if you want to have multiple calls to request.addfinalizer() and do computations that can raise in between. best, holger
def test_hello(yfix): pass
$ py.test -s test_finalizing.py ============================ test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.4.2 plugins: cov collected 1 items
test_finalizing.py E
================================== ERRORS =================================== _______________________ ERROR at setup of test_hello ________________________
request = <FixtureRequest for <Function 'test_hello'>>
@pytest.yield_fixture def yfix(request): def fin(): print "finalizing!"
0/0
E ZeroDivisionError: integer division or modulo by zero
test_finalizing.py:15: ZeroDivisionError ========================== 1 error in 0.01 seconds ==========================
Best regards, Anton
On Tue, Nov 12, 2013 at 11:16 AM, holger krekel <holger@merlinux.eu> wrote:
Hi Andrii,
On Mon, Nov 11, 2013 at 19:56 +0200, Andrii Smirnov wrote:
Hello All,
We have complex enough (several stages of putting the test environment into some condition) code which should be executed in all cases regardless of test setup result (fixture setup).
Since finalizer for fixture will not be called in case its (fixture) setup failed we've put some calls to pytest_sessionfinish as a temporary workaround but we need to find a way how to call finalizer code explicitly.
Calling fixture finalizers from such a hook is hard if even possible.
But i don't understand yet why your finalizers are not run. Take this example::
import pytest
@pytest.fixture def fix(request): def fin(): print "finalizing!"
request.addfinalizer(fin) 0/0
def test_hello(fix): pass
If you run this with ``py.test -s`` you will see the ``finalizing!`` message although the fixture function fails.
If you are running xUnit-style ``setup*`` functions then indeed, pytest is compatible to the way unittest or nose do xUnit setup: teardownX functions are not run if a setupX function fails. However, you can transform any such setup function into a pytest style one by puttig a fixture-autouse decorator in front::
@pytest.fixture(autouse=True) def setup_function(request): # as above you can register finalizers etc.
If you use the decorator you can also use other pytest fixtures such as ``tmpdir`` or ``monkeypatch`` or your own fixtures, of course.
If both examples don't answer your question, please try to give a code example on how things fail for you.
cheers, holger _______________________________________________ Pytest-dev mailing list Pytest-dev@python.org https://mail.python.org/mailman/listinfo/pytest-dev
participants (3)
-
Andrii Smirnov -
Anton P -
holger krekel