I am trying to share class scope and method scope fixtures across different classes using pytest. Currently, I get a syntax error if I try to add a fixture from another class as shown below.
I am aware that one way to work around this is to not have the fixture enclosed by a class. However, enclosing the fixtures makes sense for what I am trying to do.
import pytest
class Test_example1(object):
#classmethod
#pytest.fixture(scope='class')
def example1_fixture(self):
print("example1_fixture setup")
yield
print("example1_fixture teardown")
def test_1(self, example1_fixture):
print("class example1::test_1")
# This works if I comment out the code causing errors
#pytest.fixture(scope='class')
def global_example_fixture():
print("global_example_fixture setup")
yield
print("global_example_fixture teardown")
class Test_example2(object):
#pytest.fixture(scope='class')
def example2_fixture(self):
print("example2_fixture setup")
yield
print("example2_fixture teardown")
# Results in fixture not found error
def test_1(self, example1_fixture):
print("class example2::test_1")
# Results in syntax error
def test_2(self, Test_example1.example1_fixture, global_example_fixture):
print("class example2::test_1")
# This works...
def test_2(self, example2_fixture, global_example_fixture):
print("class example2::test_2")
I expect to be able to call the class level and method level fixtures across classes.
Related
I am working on pytest API automation project, and I need to get a random product from the DB. Is there a way that I could use the same random product for all the test cases in my class? I am using a setup class method but it generates a different product every test. Thank you.
class TestCreateOrdersSmoke:
#classmethod
def setup(cls):
cls.products_db = ProductsDao()
cls.orders_db = OrdersDao()
cls.orders_helper = OrdersHelper()
#pytest.mark.tcid48
def test_create_order_as_guest(self):
random_product = self.products_db.select_random_product_from_db()
random_product_id = random_product[0]['ID']
UPDATE:
So i used a pytest session fixture like seggested and it works so thank you! but i want to make sure that this is right practice so here is the updated code:
class TestCreateOrdersSmoke:
#pytest.fixture(scope="session")
def helpers(self):
products_db = ProductsDao()
orders_db = OrdersDao()
orders_helper = OrdersHelper()
random_product = products_db.select_random_product_from_db()
yield {'products_db':products_db,
'orders_db':orders_db,
'orders_helper':orders_helper,
'random_product':random_product}
#pytest.mark.tcid48
def test_create_order_as_guest(self, helpers):
random_product = helpers['random_product']
random_product_id = random_product[0]['ID']
#pytest.mark.tcid88
def test_create_order_with_new_user(self, helpers):
random_product = helpers['random_product']
random_product_id = random_product[0]['ID']
As you say, you need a fixture for all methods in class, so you can use "class" or "session" scope fixture #pytest.fixture(scope="class").
Here some ways to organize the code with the "class" or "session" fixtures.
First way: fixture with "class" scope can be inside a class, example is the same as you did with "session" fixture:
class TestCreateOrdersSmoke:
#pytest.fixture(scope="class")
Second way: fixture with "class" scope can be outside of the class, so then you can use it in different classes, example:
import logging
#pytest.fixture(scope="class")
def h():
logging.info('h')
class TestOne:
def test_one_one(self, h):
logging.info('test_one_one')
def test_one_two(self, h):
logging.info('test_one_two')
class TestTwo:
def test_two_one(self, h):
logging.info('test_two_one')
Third way: you can annotate class with a fixture by marking #pytest.mark.usefixtrures('fixture_name') and you don't need to pass fixture to each method of the class, it will be passed automatically. Example:
import logging
#pytest.fixture(scope="class")
def h():
logging.info('h')
#pytest.mark.usefixtures('h')
class TestOne:
def test_one_one(self):
logging.info('test_one_one')
def test_one_two(self):
logging.info('test_one_two')
And you can try to use 'autouse' fixture param, so you don't need to pass fixture inside methods, or annotate class with it. Example:
#pytest.fixture(scope="class", autouse=True)
def h():
logging.info('h')
class TestOne:
def test_one_one(self):
logging.info('test_one_one')
def test_one_two(self):
logging.info('test_one_two')
But i don't recommend to use autouse, be aware from use it.
I am working on a Django project and some unittests seemed to be failing seemingly unexpectedly. I was able to track down the failures to how it seems the VSCode/unittest testing framework is calling the test cases. I was able to reproduce the behavior with the simple setup below.
import unittest
class USER_STORY_1_8_1(unittest.TestCase):
def setUp(self):
print('USER_STORY_1_8_1:setUp')
def tearDown(self):
print('USER_STORY_1_8_1:tearDown')
def test_run(self):
print('USER_STORY_1_8_1:test_run')
class USER_STORY_1_8_10(unittest.TestCase):
def setUp(self):
print('USER_STORY_1_8_10:setUp')
def tearDown(self):
print('USER_STORY_1_8_10:tearDown')
def test_run(self):
print('USER_STORY_1_8_10:test_run')
class USER_STORY_1_8_11(unittest.TestCase):
def setUp(self):
print('USER_STORY_1_8_11:setUp')
def tearDown(self):
print('USER_STORY_1_8_11:tearDown')
def test_run(self):
print('USER_STORY_1_8_11:test_run')
Screen Capture of VSCode project Here
It seems that for similarly named test cases like these:
class USER_STORY_1_8_1(unittest.TestCase)
class USER_STORY_1_8_10(unittest.TestCase)
class USER_STORY_1_8_11(unittest.TestCase)
instead of calling each one in an exact-match type of way, it's doing some kind of 'USER_STORY_1_8_1.*' ordered resolution so that a call to USER_STORY_1_8_1 actually calls into the setUp() for USER_STORY_1_8_11. If USER_STORY_1_8_11 is unavailable (e.g. commented out), then i resolves to USER_STORY_1_8_10. And if neither is available, only then it calls the correct USER_STORY_1_8_1.
Is there anyway to override this behavior?
I have a function scoped fixture.
import pytest
#pytest.fixture(scope="function")
def some_fixture(req):
print "This is not the end"
return "okay"
Is it possible to invoke the fixture in the setup_method somehow.?
Something like the following snippet...
class TestOne(object):
def setup_method(self, method, some_fixture): # this would give argument error
print "okay"
def test_one(self):
pass
I know fixture would work same as setup_method, but I have got a very corner case scenario and I want the fixture to be executed in setup_method itself.
You can mark your setup_method as fixture & then call it in your tests.
class TestOne(object):
#pytest.fixture(scope="class")
def setup_method(self, method, some_fixture): # this would give argument error
print "okay"
def test_one(self, setup_method):
pass
Is there a function that is fired at the beginning/end of a scenario of tests? The functions setUp and tearDown are fired before/after every single test.
I typically would like to have this:
class TestSequenceFunctions(unittest.TestCase):
def setUpScenario(self):
start() #launched at the beginning, once
def test_choice(self):
element = random.choice(self.seq)
self.assertTrue(element in self.seq)
def test_sample(self):
with self.assertRaises(ValueError):
random.sample(self.seq, 20)
for element in random.sample(self.seq, 5):
self.assertTrue(element in self.seq)
def tearDownScenario(self):
end() #launched at the end, once
For now, these setUp and tearDown are unit tests and spread in all my scenarios (containing many tests), one is the first test, the other is the last test.
As of 2.7 (per the documentation) you get setUpClass and tearDownClass which execute before and after the tests in a given class are run, respectively. Alternatively, if you have a group of them in one file, you can use setUpModule and tearDownModule (documentation).
Otherwise your best bet is probably going to be to create your own derived TestSuite and override run(). All other calls would be handled by the parent, and run would call your setup and teardown code around a call up to the parent's run method.
I have the same scenario, for me setUpClass and tearDownClass methods works perfectly
import unittest
class Test(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls._connection = createExpensiveConnectionObject()
#classmethod
def tearDownClass(cls):
cls._connection.destroy()
Here is an example: 3 test methods access a shared resource, which is created once, not per test.
import unittest
import random
class TestSimulateLogistics(unittest.TestCase):
shared_resource = None
#classmethod
def setUpClass(cls):
cls.shared_resource = random.randint(1, 100)
#classmethod
def tearDownClass(cls):
cls.shared_resource = None
def test_1(self):
print('test 1:', self.shared_resource)
def test_2(self):
print('test 2:', self.shared_resource)
def test_3(self):
print('test 3:', self.shared_resource)
For python 2.5, and when working with pydev, it's a bit hard. It appears that pydev doesn't use the test suite, but finds all individual test cases and runs them all separately.
My solution for this was using a class variable like this:
class TestCase(unittest.TestCase):
runCount = 0
def setUpClass(self):
pass # overridden in actual testcases
def run(self, result=None):
if type(self).runCount == 0:
self.setUpClass()
super(TestCase, self).run(result)
type(self).runCount += 1
With this trick, when you inherit from this TestCase (instead of from the original unittest.TestCase), you'll also inherit the runCount of 0. Then in the run method, the runCount of the child testcase is checked and incremented. This leaves the runCount variable for this class at 0.
This means the setUpClass will only be ran once per class and not once per instance.
I don't have a tearDownClass method yet, but I guess something could be made with using that counter.
import unittest
class Test(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.shared_data = "dddd"
#classmethod
def tearDownClass(cls):
cls.shared_data.destroy()
def test_one(self):
print("Test one")
def test_two(self):
print("Test 2")
For more visit Python
unit test document
I'm researching new version of pytest (2.3) and getting very excited about the new functionality where you
"can precisely control teardown by registering one or multiple
teardown functions as soon as they have performed some actions which
need undoing, eliminating the no need for a separate “teardown”
decorator"
from here
It's all pretty clear when it's used as function, but how to use it in the class?
class Test(object):
#pytest.setup(scope='class')
def stp(self):
self.propty = "something"
def test_something(self):
... # some code
# need to add something to the teardown
def test_something_else(self):
... # some code
# need to add even more to the teardown
Ok, I got it working by having a 'session'-wide funcarg finalizer:
#pytest.fixture(scope = "session")
def finalizer():
return Finalizer()
class Finalizer(object):
def __init__(self):
self.fin_funcs = []
def add_fin_func(self, func):
self.fin_funcs.append(func)
def remove_fin_func(self, func):
try:
self.fin_funcs.remove(func)
except:
pass
def execute(self):
for func in reversed(self.fin_funcs):
func()
self.fin_funcs = []
class TestSomething(object):
#classmethod
#pytest.fixture(scope = "class", autouse = True)
def setup(self, request, finalizer):
self.finalizer = finalizer
request.addfinalizer(self.finalizer.execute)
self.finalizer.add_fin_func(lambda: some_teardown())
def test_with_teardown(self):
#some test
self.finalizer.add_fin_func(self.additional_teardown)
def additional_teardown(self):
#additional teardown
Thanks #hpk42 for answering e-mails and helping me get the final version.
NOTE: together with xfailing the rest of the steps and improved scenarios this now makes a pretty good Test-Step structure
Indeed, there are no good examples for teardown yet. The request object has a addfinalizer method. Here is an example usage:
#pytest.setup(scope=...)
def mysetup(request):
...
request.addfinalizer(finalizerfunction)
...
The finalizerfunction will be called when all tests withing the scope finished execution.