Run code before and after each test in py.test?

核能气质少年 提交于 2019-11-27 13:25:13

问题


I want to run additional setup and teardown checks before and after each test in my test suite. I've looked at fixtures but not sure on whether they are the correct approach. I need to run the setup code prior to each test and I need to run the teardown checks after each test.

My use-case is checking for code that doesn't cleanup correctly: it leaves temporary files. In my setup I will check the files and in the teardown I also check the files. If there are extra files I want the test to fail.


回答1:


py.test fixtures are a technically adequate method to achieve your purpose.

You just need to define a fixture like that:

@pytest.fixture(autouse=True)
def run_around_tests():
    # Code that will run before your test, for example:
    files_before = # ... do something to check the existing files
    # A test function will be run at this point
    yield
    # Code that will run after your test, for example:
    files_after = # ... do something to check the existing files
    assert files_before == files_after

By declaring your fixture with autouse=True, it will be automatically invoked for each test function defined in the same module.

That said, there is one caveat. Asserting at setup/teardown is a controversial practice. I'm under the impression that the py.test main authors do not like it (I do not like it either, so that may colour my own perception), so you might run into some problems or rough edges as you go forward.




回答2:


Fixtures are exactly what you want. That's what they are designed for.

Whether you use pytest style fixtures, or setup and teardown (module, class, or method level) xUnit style fixtures, depends on the circumstance and personal taste.

From what you are describing, it seems like you could use pytest autouse fixtures.
Or xUnit style function level setup_function()/teardown_function().

Pytest has you completely covered. So much so that perhaps it's a fire hose of information.




回答3:


You may use decorators but programatically, so you don't need to put the decorator in each method.

I'm assuming several things in next code:

The test methods are all named like: "testXXX()" The decorator is added to the same module where test methods are implemented.

def test1():
    print ("Testing hello world")

def test2():
    print ("Testing hello world 2")

#This is the decorator
class TestChecker(object):
    def __init__(self, testfn, *args, **kwargs):
        self.testfn = testfn

    def pretest(self):
        print ('precheck %s' % str(self.testfn))
    def posttest(self):
        print ('postcheck %s' % str(self.testfn))
    def __call__(self):
        self.pretest()
        self.testfn()
        self.posttest()


for fn in dir() :
    if fn.startswith('test'):
        locals()[fn] = TestChecker(locals()[fn])

Now if you call the test methods...

test1()
test2()

The output should be something like:

precheck <function test1 at 0x10078cc20>
Testing hello world
postcheck <function test1 at 0x10078cc20>
precheck <function test2 at 0x10078ccb0>
Testing hello world 2
postcheck <function test2 at 0x10078ccb0>

If you have test methods as class methods, the approach is also valid. For instance:

class TestClass(object):
    @classmethod
    def my_test(cls):
        print ("Testing from class method")

for fn in dir(TestClass) :
    if not fn.startswith('__'):
        setattr(TestClass, fn, TestChecker(getattr(TestClass, fn)))

The call to TestClass.my_test() will print:

precheck <bound method type.my_test of <class '__main__.TestClass'>>
Testing from class method 
postcheck <bound method type.my_test of <class '__main__.TestClass'>>



回答4:


You can use Module level setup/teardown Fixtures of Pytest.

Here's the Link

http://pytest.org/latest/xunit_setup.html

It Works as follows:

 def setup_module(module):
     """ setup any state specific to the execution of the given module."""

 def teardown_module(module):
     """ teardown any state that was previously setup with a setup_module
     method."""

 Test_Class():
        def test_01():
          #test 1 Code

It will call setup_module before this test and teardown_module after test completes.

You can include this fixture in each test-script to run it for each test.

IF you want to use something that is common to all tests in a directory You can use package/directory level fixtures nose framework

http://pythontesting.net/framework/nose/nose-fixture-reference/#package

In __init__.py file of the package you can include following

     def setup_package():
       '''Set up your environment for test package'''

     def teardown_package():
        '''revert the state '''



回答5:


Fixtures by default have scope=function. So, if you just use a definition such as

@pytest.fixture
def fixture_func(self)

It defaults to (scope='function').

So any finalizes in the fixture function will be called after each test.

Ref: 1. http://programeveryday.com/post/pytest-creating-and-using-fixtures-for-streamlined-testing/



来源:https://stackoverflow.com/questions/22627659/run-code-before-and-after-each-test-in-py-test

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!