I have some file for unit test with django:
test1.py
class Test1(unittest.TestCase):
def setUp(self):
...
def tearDown(self):
...
test1.py
class Test1(unittest.TestCase):
def setUp(self):
...
def tearDown(self):
...
testn.py
class Testn(unittest.TestCase):
def setUp(self):
...
def tearDown(self):
...
I want to create a global setup to make some configuration for it all test, someting like:
some_file.py
class GlobalSetUpTest(SomeClass):
def setup(self): # or any function name
global_stuff = "whatever"
is that possible? if so, how? Thanks in advance.
You could just create a parent class with your custom global setUp method and then have all of your other test classes extend that:
class MyTestCase(unittest.TestCase):
def setUp(self):
self.global_stuff = "whatever"
class TestOne(MyTestCase):
def test_one(self):
a = self.global_stuff
class TestTwo(MyTestCase):
def setUp(self):
# Other setUp operations here
super(TestTwo, self).setUp() # this will call MyTestCase.setUp to ensure self.global_stuff is assigned.
def test_two(self):
a = self.global_stuff
Obviously you could use the same technique for a 'global' tearDown method.
If you want to have it only run once for all tests, you can override the test management command by placing a management/commands/test.py in one of your apps:
from django.core.management.commands import test
class Command(test.Command):
def handle(self, *args, **options):
# Do your magic here
super(Command, self).handle(*args, **options)
Unfortunately this does not work well with PyCharm.
In PyCharm you can use the "Before Lunch" Task instead.
Related
How can I add simple test method from unittest.TestCase to TestSuite. As I see it is only possible to add whole class only to suite, for example I want something like this:
import unittest
class MyBaseTestCase(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.abs = "test"
class MyTestClass(MyBaseTestCase):
def test_abs(self):
if self.abs:
pass
class MyTestSuite(unittest.TestSuite):
def __init__(self):
super().__init__()
self.addTest(MyTestClass.test_abs)
Here I get an error: AttributeError: 'TeamcityTestResult' object has no attribute 'abs'. It seems like it runs as a test, but setUpClass does not calls.
How did you run the test suite? I used your code and ran it using 'python3 -m unittest test.py':
import unittest
class MyBaseTestCase(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.abs = "test"
class MyTestClass(MyBaseTestCase):
def test_abs(self):
if self.abs:
pass
class MyTestSuite(unittest.TestSuite):
def __init__(self):
super().__init__()
self.addTest(MyTestClass.test_abs)
And it works.
Let's say I have my unittest set up like this:
import unittest
class BaseTest(object):
def setup(self):
self.foo = None
def test_something(self):
self.assertTrue(self.foo.something())
def test_another(self):
self.assertTrue(self.foo.another())
def test_a_third_thing(self):
self.assertTrue(self.foo.a_third_thing())
class TestA(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooA()
class TestB(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooB()
class TestC(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooC()
Now let's say FooC doesn't have a_third_thing implemented yet, and I want to skip test_a_third_thing for ONLY the TestC class. Is there some way I can use the #unittest.skipif decorator to do this? Or some other handy way to skip this test for only this class?
Python 2.7, in case it matters
You may not need to "skip" the test. One simple approach is to override the base test with a dummy.
class TestC(BaseTest, unittest.TestCase):
def setup(self):
self.foo = FooC()
def test_a_third_thing(self):
"""Override the assertions of the base test."""
pass
You cannot use #unittest.skipif here because it is evaluated during module, and the check needed should be run during runtime.
To achieve desired result your test_a_third_thing in base class should look like this:
class BaseTest(unittest.TestCase):
def test_a_third_thing(self):
if not getattr(self.foo, "a_third_thing", None):
self.skipTest(self.foo.__class__.__name__ + ' has no a_third_thing, skip')
else:
self.assertTrue(self.foo.a_third_thing())
Also fix typos in your example setup to setUp. Remove 'unittest.TestCase' from inheritance list of test classes and add to base class.
class MyTestCase(unittest.Testcase):
def setUp(self):
self.something = True
#pytest.fixture(autouse=True)
def MyTestMethod(self, frozentime):
fn(self.something) # self.something is NOT defined
If I use #pytest.fixture(autouse=True) I end up with some strange behavior from PyTest. Instead of calling my setUp method before the test method, PyTest skips the setUp and calls MyTestMethod as if it was a PyTest MyTestFunction which of course does not work very well.
How do I get MyTestMethod to use the frozentime fixture without ignoring the setUp method that should be called first.
class MyTestCase(unittest.Testcase):
def setUp(self):
self.something = True
##pytest.fixture(autouse=True)
def MyTestMethod(self, frozentime): # Fails on call, because it needs too many arguments.
fn(self.something)
That's because the autouse fixtures are executed before the setUp/tearDown methods:
Note
Due to architectural differences between the two frameworks, setup and teardown for unittest-based tests is performed during the call phase of testing instead of in pytest‘s standard setup and teardown stages. This can be important to understand in some situations, particularly when reasoning about errors. For example, if a unittest-based suite exhibits errors during setup, pytest will report no errors during its setup phase and will instead raise the error during call.
Source
There's nothing you can do to work around this behaviour. You can either move the fixture-relevant code out of setUp/tearDown methods, for example: if self.flag is used in class-scoped fixtures, you can replace
class Tests(unittest.TestCase):
def setUp(self):
self.flag = True
def tearDown(self):
self.flag = False
#pytest.fixture(autouse=True)
def myfixture(self):
print(self.flag)
with
class Tests(unittest.TestCase):
#pytest.fixture(autouse=True)
def prepare_flag(self):
self.flag = True
yield
self.flag = False
#pytest.fixture(autouse=True)
def myfixture(self, prepare_flag):
print(self.flag)
Or you can move all the setUp relevant code from fixtures:
class Tests(unittest.TestCase):
def setUp(self):
self.flag = True
#pytest.fixture(autouse=True)
def myfixture(self, somearg):
fn(self.flag, somearg)
becomes
class Tests(unittest.TestCase):
def setUp(self):
self.flag = True
fn(self.flag, self._somearg)
#pytest.fixture(autouse=True)
def assign_stuff(self, somearg):
self._somearg = somearg
As #hoefling mentioned, the two lifecycles are incompatible... but that can be hacked around if you're not aiming for drop-in compatibility.
import pytest
from pytestqt.plugin import QtBot
from unittest import TestCase
from myproject import custom_widget
#pytest.fixture(scope="class")
def qtbot_adapter(qapp, request):
"""Adapt qtbot fixture for usefixtures and unittest.TestCase"""
request.cls.qtbot = QtBot(request)
def with_updown(function):
"""Wrapper to bodge setUp/tearDown into fixtures+TestCase"""
def test_wrapper(self, *args, **kwargs):
__tracebackhide__ = True
if callable(getattr(self, 'up', None)):
self.up()
try:
function(self, *args, **kwargs)
finally:
if callable(getattr(self, 'down', None)):
self.down()
test_wrapper.__doc__ = function.__doc__
return test_wrapper
#pytest.mark.usefixtures("qtbot_adapter")
class MyTestCase(TestCase):
def up(self):
self.widget = custom_widget.CustomWidget()
self.widget.show()
#with_updown
def test_some_property(self):
with self.qtbot.waitSignal(self.widget.my_signal,
timeout=300):
self.widget.do_thing()
self.assertEqual(self.widget.get_thing(), 'foo')
When running a simple unittest it would sometimes be easier to be able to keep the tests inside the class. However, I don't know how to reload the current module, and so whenever that's needed I have to move the tests into a separate module. Is there a way around this?
module: foo
import unittest
class MyObject
...
class MockMyObject
...
class TestMock(unittest.TestCase):
def setUp(self):
MyObject = MockMyObject
mocked = MyObject()
def tearDown(self):
reload(foo) # what goes here?
def testFunction(self):
mocked.do_mocked_function()
if __name__ == "__main__":
unittest.main()
The way I've found to handle this is to import sys and reload(sys.modules[__name__]) in the tearDown method, but I'm wondering if there is a better method.
You can save your original class in a variable and restore it in the tearDown function.
Here is an example:
class TestMock(unittest.TestCase):
original = MyObject
def setUp(self):
global MyObject
MyObject = MockMyObject
def tearDown(self):
global MyObject
MyObject = TestMock.original
def testFunction(self):
MyObject().do_mocked_function()
that's not a good idea to reload your module.
class TestMock(unittest.TestCase):
def setUp(self):
MyObject = MockMyObject
self.mocked = MyObject()
def tearDown(self):
pass
def testFunction(self):
self.mocked.do_mocked_function()
For unit tests (using the unittest module) that use the App Engine testbed, I need setUp and tearDown methods to activate and deactivate the testbed, respectively (slightly simplified):
class SomeTest(unittest.TestCase):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
def tearDown(self):
self.testbed.deactivate()
def testSomething(self):
...
This quickly becomes a burden to write. I could write a base class TestCaseWithTestbed, but then I'd have to remember to call the superclass method each time I need a custom setUp in one of the test cases.
I thought it would be more elegant to solve this with a class decorator instead. So I'd like to write:
#WithTestbed
class SomeTest(unittest.TestCase):
def testSomething(self):
...
With this decorator applied, the testbed should just be activated magically. So... how to implement the WithTestbed decorator? I currently have the following:
def WithTestbed(cls):
class ClsWithTestbed(cls):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
cls.setUp(self)
def tearDown(self):
cls.tearDown(self)
self.testbed.deactivate()
return ClsWithTestbed
This works for simple cases, but has some serious problems:
The name of the test class becomes ClsWithTestbed and this shows up in the test output.
Concrete test classes calling super(SomeTestClass, self).setUp() end up in an infinite recursion, because SomeTestClass is now equal to WithTestbed.
I'm a bit hazy on Python's runtime type manipulation. So, how to do this the Right Way?
This appears to work and solve the problems:
def WithTestbed(cls):
def DoNothing(self):
pass
orig_setUp = getattr(cls, 'setUp', DoNothing)
orig_tearDown = getattr(cls, 'tearDown', DoNothing)
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
orig_setUp(self)
def tearDown(self):
orig_tearDown(self)
self.testbed.deactivate()
cls.setUp = setUp
cls.tearDown = tearDown
return cls
Does anyone see any problems with this approach?
Here's a simple way to do what you're asking with subclassing instead of a decorator:
class TestCaseWithTestBed(unittest.TestCase):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self.mySetUp()
def tearDown(self):
self.myTearDown()
self.testbed.deactivate()
def mySetUp(self): pass
def myTearDown(self): pass
class SomeTest(TestCaseWithTestBed):
def mySetUp(self):
"Insert custom setup here"
All you have to do is define mySetUp and myTearDown in your test cases instead of setUp and tearDown.
Something like this would work:
def WithTestbed(cls):
cls._post_testbed_setUp = getattr(cls, 'setUp', lambda self : None)
cls._post_testbed_tearDown = getattr(cls, 'tearDown', lambda self : None)
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self._post_testbed_setUp()
def tearDown(self):
self.testbed.deactivate()
self._post_testbed_tearDown()
cls.setUp = setUp
cls.tearDown = tearDown
return cls
#WithTestbed
class SomeTest(object):
...