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
Related
Assume we have:
#pytest.fixture()
def setup():
print('All set up!')
return True
def foo(setup):
print('I am using a fixture to set things up')
setup_done=setup
I'm looking for a way to get to know caller function name (in this case: foo) from within setup fixture.
So far I have tried:
import inspect
#pytest.fixture()
def setup():
daddy_function_name = inspect.stack()[1][3]
print(daddy_function_name)
print('All set up!')
return True
But what gets printed is: call_fixture_func
How do I get foo from printing daddy_function_name?
You can use the built-in request fixture in your own fixture:
The request fixture is a special fixture providing information of the requesting test function.
Its node attribute is the
Underlying collection node (depends on current request scope).
import pytest
#pytest.fixture()
def setup(request):
return request.node.name
def test_foo(setup):
assert setup == "test_foo"
How to pass custom arguments to fixture inside test method of unittest.TestCase derived class using pytest?
After searching for definitely too long time I managed to invent solution with usage of doc and threads about wrapping fixtures. I hope somebody will find it useful.
conftest.py
import pytest
#pytest.fixture()
def add(request):
def wrapped(a=10, b=5):
return a + b
request.cls.add = wrapped
add_test.py
import pytest
from unittest import TestCase
#pytest.mark.usefixtures('add')
class AddTestCase(TestCase):
def test_add(self):
# parameters can be passed inside test method
result = self.add(2, 2)
assert result == 4
I am trying to patch some functions during either the setUp or setUpClass methods of a unittest.TestCase subclass.
Given a module patch_me_not.py
# patch_me_not.py
def patch_me(at):
print('I am not patched at {}.'.format(at))
def patch_me_not(at):
patch_me(at)
The following script produces more output that I would expect.
# main.py
import unittest
from unittest.mock import patch
from patch_me_not import patch_me_not
#patch('patch_me_not.patch_me', lambda x: None)
class PatchMeNotTests(unittest.TestCase):
#classmethod
def setUpClass(cls):
print('I am the setUpClass.')
patch_me_not('setUpClass')
def setUp(self):
print('I am the setUp.')
patch_me_not('setUp')
def test_print(self):
print('I am the test')
patch_me_not('test_print')
if __name__ == '__main__':
unittest.main()
The test script output is
I am the setUpClass.
I am not patched at setUpClass.
I am the setUp.
I am not patched at setUp.
I am the test
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Where I would not expect the two "I am not patched at..." lines in the output if the patch worked in setUp and setUpClass.
How can I get the mock patch to be applied in these methods?
I think you need to do this:
class PatchMeNotTests(unittest.TestCase):
#classmethod
#patch('patch_me_not.patch_me', lambda x: None)
def setUpClass(cls):
print('I am the setUpClass.')
patch_me_not('setUpClass')
#patch('patch_me_not.patch_me', lambda x: None)
def setUp(self):
print('I am the setUp.')
patch_me_not('setUp')
def test_print(self):
print('I am the test')
patch_me_not('test_print')
Patching your test case did not work because when patch is applied to TestCase it patches only test methods or to be more specific: methods that start with a configurable prefix patch.TEST_PREFIX which default value is "test". That's why your solution did not work.
Here is relevant quote from unittest docs
Patch can be used as a TestCase class decorator. It works by
decorating each test method in the class. This reduces the boilerplate
code when your test methods share a common patchings set. patch()
finds tests by looking for method names that start with
patch.TEST_PREFIX. By default, this is 'test', which matches the way
unittest finds tests. You can specify an alternative prefix by setting
patch.TEST_PREFIX.
I need to test smth on python via ssh. I don't want to make ssh connection for every test, because it is to long, I have written this:
class TestCase(unittest.TestCase):
client = None
def setUp(self):
if not hasattr(self.__class__, 'client') or self.__class__.client is None:
self.__class__.client = paramiko.SSHClient()
self.__class__.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.__class__.client.connect(hostname=consts.get_host(), port=consts.get_port(), username=consts.get_user(),
password=consts.get_password())
def test_a(self):
pass
def test_b(self):
pass
def test_c(self):
pass
def disconnect(self):
self.__class__.client.close()
and my runner
if __name__ == '__main__':
suite = unittest.TestSuite((
unittest.makeSuite(TestCase),
))
result = unittest.TextTestRunner().run(suite)
TestCase.disconnect()
sys.exit(not result.wasSuccessful())
In this version I get error TypeError: unbound method disconnect() must be called with TestCase instance as first argument (got nothing instead). So how i can call disconnect after all tests pass?
With best regards.
You should use setUpClass and tearDownClass instead, if you want to keep the same connection for all tests. You'll also need to make the disconnect method static, so it belongs to the class and not an instance of the class.
class TestCase(unittest.TestCase):
def setUpClass(cls):
cls.connection = <your connection setup>
#staticmethod
def disconnect():
... disconnect TestCase.connection
def tearDownClass(cls):
cls.disconnect()
you can do it by defining startTestRun,stopTestRun of unittest.TestResult class. setUpClass and tearDownClass are running per test class(per test file) so if you have multiple files this methods will run for each one.
by adding following code to my tests/__init__.py i managed to achieve it. this code runs only once for all tests(regardless of number of test classes and test files).
def startTestRun(self):
"""
https://docs.python.org/3/library/unittest.html#unittest.TestResult.startTestRun
Called once before any tests are executed.
:return:
"""
DockerCompose().start()
setattr(unittest.TestResult, 'startTestRun', startTestRun)
def stopTestRun(self):
"""
https://docs.python.org/3/library/unittest.html#unittest.TestResult.stopTestRun
Called once after all tests are executed.
:return:
"""
DockerCompose().compose.stop()
setattr(unittest.TestResult, 'stopTestRun', stopTestRun)
There seems to be a simple solution for the basic (beginner's) case:
def tmain():
setup()
unittest.main(verbosity=1, exit=False)
clean()
The trick is "exit=False" which lets the function tmain run until the end.
setup() and clean() can be any functions to do what the name implies.
I want to set a conditional decorator to the setUpClass in python's unitest. I have tried the following (without a condition for now, to demonstrate the point):
import unittest
class conditional_decorator(object):
def __call__(self, func):
print ("Extra output")
return func
class First(unittest.TestCase):
#classmethod
#conditional_decorator
def setUpClass(cls):
print ("setting up")
def test1(self):
pass
if __name__ == '__main__':
unittest.main()
but I get an error
TypeError: object.__new__() takes no parameters
How can I solve this problem? Moreover, is there an easy way to 'combine' the two decorators for the setUpClass method?
When you look at the traceback line it will tell you where your error occurred. My best guess, because I dont know the rest of your code, is that in the body of your code you left an extra parameter or added an extra comma.
As for two decorators that questioned was asked here:Can I combine two decorators into a single one in Python?
*Also remove Class from setUpClass because setUp is it's own function
Just instantiate your conditional_decorator class first:
class First(unittest.TestCase):
#classmethod
#conditional_decorator() # Note the class is instantiated first.
def setUpClass(cls):
print ("setting up")
def test1(self):
pass
Or use a function instead of a class as your decorator:
def conditional_decorator(func):
print ("Extra output")
return func
class First(unittest.TestCase):
#classmethod
#conditional_decorator
def setUpClass(cls):
print ("setting up")
def test1(self):
pass
if __name__ == '__main__':
unittest.main()
Now it works:
$ python my_test.py
Extra output
setting up
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK