Does the setUp method from the unittest.TestCase knows what is the next test case that will be executed? For example:
import unittest
class Tests(unittest.TestCase):
def setUp(self):
print "The next test will be: " + self.next_test_name()
def test_01(self):
pass
def test_02(self):
pass
if __name__ == '__main__':
unittest.main()
Such code should produce upon execution:
The next test will be: test_01
The next test will be: test_02
No, unittest makes no guarantee about the order of test execution.
Moreover, you should structure your unit tests not to rely on any particular order. If they require some state setup from another test method then you no longer have, by definition, a unit test.
The current test method name which will be executed lives in self._testMethodName, but use it at your own risk (accessing _private attributes is subject to breakage without warning). Do not use this to customise setUp based on the particular test method, prefer to split tests requiring a different setup off into separate test classes.
class Tests(unittest.TestCase):
def setUp(self):
print "The next test will be: " + self.id()
def test_01(self):
pass
def test_02(self):
pass
if __name__ == '__main__':
unittest.main()
Which will produce:
The next test will be: __main__.Tests.test_01
The next test will be: __main__.Tests.test_02
Related
I am having issues changing object variables within class method. Example:
import unittest
class Example(unittest.TestCase):
def setUp(self):
self.var_A = "foo"
def test_1(self):
self.assertEqual(self.var_A, "foo")
self.var_A = "bar"
def test_2(self):
self.assertEqual(self.var_A, "bar")
if __name__ == '__main__':
unittest.main()
test_2 fails as self.var_A value has not been changed to "bar" in test_1
If I try to place it outside setUp and change it via self.__class__.var_A , it works.
Working example:
import unittest
class Example(unittest.TestCase):
var_A = "foo"
def setUp(self):
pass
def test_1(self):
self.assertEqual(self.var_A, "foo")
self.__class__.var_A = "bar"
def test_2(self):
self.assertEqual(self.var_A, "bar")
if __name__ == '__main__':
unittest.main()
Question: Why is the second example working and the first isn't?
It is confusing because it appears self.var_A is immutable and can not be changed after setUp, but I can use it as a part of the object within other test methods
The test runner will execute the setUp() method for each test method, so attributes defined in setUp() are reset each time. That's intentional and documented FWIW - you don't want your tests to depend on each other.
Class attributes on the other hand are left alone, which is why your second example "works".
Note that there's also a setUpClass method that is only executed once for all tests in the testcase, but you should only use it for attributes that are 1/ read-only and 2/ costly to set up. Once again, your tests should NOT depend on side-effects from other tests, each test MUST work in isolation, and each test must work whatever other tests from the same testcase have been (or not) executed before.
In nose, the teardown runs regardless if setup has completed successfully or the status of the test run.
I want to perform a task in teardown that is only executed if the test that just ran failed. Is there an easy way to retrieve the result of each individual test case and pass it to the teardown method to be interpreted?
class TestMyProgram:
def setup(self):
# setup code here
def teardown(self):
# teardown code here
# run this code if test failed
if test_result == 'FAIL':
# do something
def test_one(self):
# example test placeholder
pass
def test_two(self):
# example test placeholder
pass
You have to capture the state of the test, and pass it on to your teardown method. The state of the test is within nose code: you cannot access without writing a nose plugin. But even with plugin, you would have to write a custom rig to pass on the state to the teardown method. But if you are willing to break the structure of the code a little bit to accommodate your request, you might be able to do something like this:
def special_trardown(self, state):
# only state specific logic goes here
print state
def test_one_with_passing_state(self):
try:
test_one(self)
except AssertionError as err:
test_result = "FAIL"
self.special_teardown(test_result)
raise
Its not perfect, but it makes the flow of events obvious to other people looking at your tests. You can also wrap it up as decorator / context manager for more syntactic sugar.
I have a python unitest script with an double inheritance of the TestCase as follows:
import unittest
class Upper(unittest.TestCase):
def test_dummy(self):
pass
class Lower(Upper):
pass
if __name__ == '__main__':
unittest.main()
The idea is to define an upper class with a test method implementation, and derive from this class (in different subdirectories) which contain some additional setup functionality. In the end, there is one upper.py from which many different test_lower.py are derived. The test methods are ONLY implemented in upper.py.
Given the example above now I do a python test_example.py only to see that python is trying to run 2 tests! The script contains exactly one test, so why is unittest executing two tests?
I assume that unittest finds one test within Lower and one test in Upper somehow, but I only want to execute the test which is found in Lower (because of additional and required setup functionalities). How can I achieve this?
Context In the real case the two classes are defined in two different files, residing in two directories. Maybe this helps.
Unittest library iterates over a TestCase subclass attributes, finding methods which start with test_. In case of Lower test case it inherits a method from its parent, so it is executed twice - once inside Upper test case and second time inside Lower class.
If both of the test cases are meant to be run, the only solution i see is to make a take out test_dummy test to an other subclass of Upper
If you want a test to be run in a parent class, but skipped in some of its subclasses, try this:
import unittest
class Upper(unittest.TestCase):
def test_dummy(self):
pass
class Lower(Upper):
def test_dummy(self):
return # skip test
#unittest.skip # or this - but ugly
def test_dummy(self):
return # skip test
if __name__ == '__main__':
unittest.main()
UPDATE:
I think now i understand what you want: you want the test method to be run only in subclasses. Then i suggest you to inherit Upper from object, and the subclasses - both from Upper and TestCase:
import unittest
class Upper(object):
def test_dummy(self):
self.assertTrue(True)
class Lower(unittest.TestCase, Upper):
pass
if __name__ == '__main__':
unittest.main()
Running:
python test2.py -v
test_dummy (__main__.Lower) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
I have a data structure that is created in one function and passed onto other functions. I am trying to unit test all those functions.
Do I need to re-create that data structure (the environment) at each function? I tried using a global variable but I cannot guarantee which test case will run before the other.
I know I cannot override __init__ of unittest.TestCase without much headache.
How else can I achieve that? Passing a parameter or somehow making it a variable and avoiding a race condition?
It sounds like you do not want to redefine the data structure before each test. As long as the tests do not modify the data, I don't think there is any problem with defining the data structure in __init__:
import unittest
class Test(unittest.TestCase):
def __init__(self, methodName = 'runTest'):
unittest.TestCase.__init__(self, methodName)
self.data = range(5)
def test_getitem(self):
self.assertEqual(self.data[1],1)
def test_reversed(self):
self.assertEqual(list(reversed(self.data)),[4,3,2,1,0])
if __name__ == '__main__':
import sys
sys.argv.insert(1,'--verbose')
unittest.main(argv = sys.argv)
yields
% test.py
test_getitem (__main__.Test) ... ok
test_reversed (__main__.Test) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
When using nosetests for Python it is possible to disable a unit test by setting the test function's __test__ attribute to false. I have implemented this using the following decorator:
def unit_test_disabled():
def wrapper(func):
func.__test__ = False
return func
return wrapper
#unit_test_disabled
def test_my_sample_test()
#code here ...
However, this has the side effect of calling wrapper as the unit test. Wrapper will always pass but it is included in nosetests output. Is there another way of structuring the decorator so that the test will not run and does not appear in nosetests output.
Nose already has a builtin decorator for this:
from nose.tools import nottest
#nottest
def test_my_sample_test()
#code here ...
Also check out the other goodies that nose provides: https://nose.readthedocs.org/en/latest/testing_tools.html
You can also use unittest.skip decorator:
import unittest
#unittest.skip("temporarily disabled")
class MyTestCase(unittest.TestCase):
...
There also is a skiptest plugin for nosetest, which will cause the test show in test output as skipped. Here is a decorator for that:
def skipped(func):
from nose.plugins.skip import SkipTest
def _():
raise SkipTest("Test %s is skipped" % func.__name__)
_.__name__ = func.__name__
return _
Example output:
$ nosetests tests
..........................................................................
..................................S.............
----------------------------------------------------------------------
Ran 122 tests in 2.160s
OK (SKIP=1)
You can just start the class, method or function name with an underscore and nose will ignore it.
#nottest has its uses but I find that it does not work well when classes derive from one another and some base classes must be ignored by nose. This happens often when I have a series of similar Django views to test. They often share characteristics that need testing. For instance, they are accessible only to users with certain permissions. Rather than write the same permission check for all of them, I put such shared test in an initial class from which the other classes derive. The problem though is that the base class is there only to be derived by the later classes and is not meant to be run on its own. Here's an example of the problem:
from unittest import TestCase
class Base(TestCase):
def test_something(self):
print "Testing something in " + self.__class__.__name__
class Derived(Base):
def test_something_else(self):
print "Testing something else in " + self.__class__.__name__
And the output from running nose on it:
$ nosetests test.py -s
Testing something in Base
.Testing something in Derived
.Testing something else in Derived
.
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
The Base class is included in the tests.
I cannot just slap #nottest on Base because it will mark the entire hierarchy. Indeed if you just add #nottest to the code above in front of class Base, then nose won't run any tests.
What I do is add an underscore in front of the base class:
from unittest import TestCase
class _Base(TestCase):
def test_something(self):
print "Testing something in " + self.__class__.__name__
class Derived(_Base):
def test_something_else(self):
print "Testing something else in " + self.__class__.__name__
And when running it _Base is ignored:
$ nosetests test3.py -s
Testing something in Derived
.Testing something else in Derived
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
This behavior is not well documented but the code that selects tests explicitly checks for an underscore at the start of class names.
A similar test is performed by nose on function and method names so it is possible to exclude them by adding an underscore at the start of the name.
I think you will also need to rename your decorator to something that has not got test in. The below only fails on the second test for me and the first does not show up in the test suite.
def unit_disabled(func):
def wrapper(func):
func.__test__ = False
return func
return wrapper
#unit_disabled
def test_my_sample_test():
assert 1 <> 1
def test2_my_sample_test():
assert 1 <> 1