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
Related
I really couldn't find a solution for :
PytestCollectionWarning: cannot collect test class 'TestBlaBla' because it has a init constructor
Here is my testing module and it needs to take the arguments outside of this file because at the end of the day I'm gonna call all test modules in a single file and run them all over different names and there is a bunch of names. I have to init them but when I run pytest it always ignores these classes. Idk how to handle without initializing them. If there is any suggestions I would be glad to hear.
tests/test_bla_bla.py
class TestBlaBla():
def __init__(self, **kwargs):
self.name1 = kwargs.get("name1")
self.name2 = kwargs.get("name2")
#pytest.fixture(scope='session')
def load_data_here(self):
return load_data(self.name1) # a function comes from a utils file. it only stands for load data and it needs take a name for path
..
"continue with test_ functions that use output of load_data_here"
tests/main.py
class TestingAll:
def __init__(self, *args, **kwargs):
self.name1 = kwargs.get("name1")
self.name2 = kwargs.get("name2")
self._process()
def _process(self):
TestBlaBla(name1 = self.name1, name2= self.name2)
TestBlaBla2(name1 = self.name1, name2= self.name2)
if __name__ == "__main__":
Test = TestingAll(name1 = "name1", name2= "name2")
Python test modules cannot have init methods as python test instantiates the class itself and there is not any way (IMHO?) to extend the instantiation and add arguments.
Yes, it is a natural idea to want to make your tests flexible by passing in command-line arguments. But you can't :-P. So you need to find another way of doing this.
Note also the if name == 'main': can work if you call the test file with python and add some code to explicitly call a py test runner. Note you do not just call your test class. A python test runner needs to be instantiated itself and run tests in a particular way.
e.g. we can have this which will allow python to instantiate and run tests in a TestingAll class (as long as it doesn't have an init method).
This uses the unittest.TextTestRunner
Note there are all sorts of python test runners, also runners like nose2 or like py.test which use a different test library.
if __name__ == '__main__':
unittest.main()
suite = unittest.TestLoader().loadTestsFromTestCase(TestingAll)
unittest.TextTestRunner(verbosity=3).run(suite)
You could maybe have an ArgsProcess class to process command line args.
Then iterate and set a global var with each value to be used and call the test runner each time.
But it depends on how your tests will be used.
The answers on this question already mentioned in comments explain and link to documentation for this warning:
py.test skips test class if constructor is defined
The answer on this question shows how an init method is replaced by using fixture:
Pytest collection warning due to __init__ constructor
Maybe something like this would work for you.
I am testing a class that needs a mock in the constructor, so I usually do this:
class TestActionManager(unittest.TestCase):
#patch('actionlib.SimpleActionClient', return_value=create_autospec(actionlib.SimpleActionClient))
def setUp(self, mock1):
self.action_manager = ActionManager()
Then in this class I add all the tests. So the first one is working fine
def test_1(self):
self.action_manager.f()
self.action_manager.f.assert_called_once()
But if I add another test and run both
def test_2(self):
self.action_manager.f()
self.action_manager.f.assert_called_once()
It says f has been called twice. I was expecting setUp to create a new ActionManager (and hence create a new mock) before starting every test, but it is clearly not happening, since the mock is somehow shared. Also I tried to do
def tearDown(self):
del self.action_manager
But it does not fix the problem.
I have read something related in
Python Testing - Reset all mocks?
where the solution is to use a different library (something that I would like to avoid)
and in Any way to reset a mocked method to its original state? - Python Mock - mock 1.0b1 where it is using different classes to do it.
Is there any possibility to reset the mock in the same class before or after every test?
BTW, this is a unittest question, not a pytest question.
Anyways,
I believe what you're looking for is reset_mock
Here's, in general, how it works:
def test_1(self):
f = MagicMock() # or whatever you're mocking
f()
f.assert_called_once()
f.reset_mock()
f()
f.assert_called_once()
The result will be PASSED
If you want to automate, then you store the mocked thing inside setUp, and in tearDown you call the mocked thing's .reset_mock() method.
def setUp(self, mock1):
self.mock1 = mock1
# ... do other things ...
def tearDown(self):
self.mock1.reset_mock()
Let's say that, for whatever reason, I want to write a set of test cases that start out from the premise of failing code.
Maybe because setting up a failure is really complicated, while the demonstrating a fixed state is simple. In my case, it's not even that, I wanted to start with a failed test and then show how to fix it, for documentation purposes.
I can decorate #unittest.expectedFailure on the base class.
But the the fixed subclasses blow up with unexpected success because the decoration is inherited.
Can I remove the expectedFailure somehow?
In the code itself, not in a command line argument?
While I use and appreciate pytest this is a question for regular unittest.
unittest.skipXXX is not what I want, I do want to run Test_ThisShouldFail's test.
import sys
import unittest
#unittest.expectedFailure
class Test_ThisShouldFail(unittest.TestCase):
""" for argument's sake, let's say
the configuration and testing is very complicated
and I want it fail by default.
Subclasses fix the issue but re-use the test code
"""
data = dict(a=1, b=2)
def test_evens(self):
for key, v in self.data.items():
self.assertFalse(v % 2, f"{key}:Odd on {v}")
## 👉???unittest.expectedSuccess????
class Test_ThisShouldWork(Test_ThisShouldFail):
""" how do I turn off the expected failure? """
def setUp(self):
self.data.update(a=10)
if __name__ == "__main__":
sys.exit(unittest.main())
output:
FAILED (expected failures=1, unexpected successes=1)
(venv) #explore$ py test_expectedfail.py -v
test_evens (__main__.Test_ThisShouldFail) ... expected failure
test_evens (__main__.Test_ThisShouldWork) ... unexpected success
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (expected failures=1, unexpected successes=1)
this didn't work:
I was hoping the MRO would look at TurnItOff's blank unittest settings and use them. No such luck.
class TurnItOff(unittest.TestCase):
pass
class Test_ThisShouldWork(TurnItOff, Test_ThisShouldFail):
....
This relies on the internal implementation of unittest.expectedFailure, but works for a start:
def expectedSuccess(test_item):
test_item.__unittest_expecting_failure__ = False
return test_item
#unittest.expectedFailure
class TestFailure(unittest.TestCase):
def test_something(self):
self.assertTrue(False)
#expectedSuccess
class TestSuccess(TestFailure):
def test_something(self):
self.assertTrue(True)
Note that test_item can be both a class or a function, depending on where you put the decorator.
Tested with Python 2.7.12 on Linux.
I am trying to write a simple function that decorates a test_* method in unittest.TestCase. I know that methods that do not begin with test_ are not considered actual tests and are not invoked directly when the test is run. I then wondered what you happen if you took a test_ method and applied a naive decorator to it that made no attempt to preserve the name. I was expecting my test to be ignored and to have to modify my decorator to make sure that the function has a name beginning with test_. I was very, very surprised when the test ran anyway.
Here's the directory layout of the example
.
|-- add.py
|-- print_args.py
|-- test_add.py
`-- test_add_decorated.py
0 directories, 4 files
add.py is the library we are testing. It adds two things.
def add(x, y):
return x + y
print_args.py is a library containing a decorator that prints the args and kwargs of a function as a side effect. It is written as naively as possible and makes no attempt to preserve the name of the function.
def print_args(wrapped):
def wrapper(*args, **kwargs):
print [args, kwargs]
return apply(wrapped, args, kwargs)
return wrapper
Here is test_add.py which imports add.py and tests that 4 + 5 = 9. The __repr__ method of TestAdd is not directly relevant to this example, but will be in the next one.
import unittest
import add
class TestAdd(unittest.TestCase):
def __repr__(self):
return "I am a unittest.TestCase! Fear me!"
def test_add(self):
self.assertEqual(add.add(4, 5), 9)
if __name__ == "__main__":
unittest.main()
When we run test_add.py, we can see that one test ran and it passed.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Now we apply the decorator to the test_add method in test_add_decorated.py.
import unittest
import print_args
import add
class TestAdd(unittest.TestCase):
def __repr__(self):
return "I am a unittest.TestCase! Fear me!"
#print_args.print_args
def test_add(self):
self.assertEqual(add.add(4, 5), 9)
if __name__ == "__main__":
unittest.main()
Before I ran this, I was expecting to see no errors, but an indication that zero tests had run, since the test_add method's name should now be wrapper.
That is not what happened. The print_args decorator worked fine, we can see the args and kwargs in an array and an indication that one test ran successfully.
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
[(I am a unittest.TestCase! Fear me!,), {}]
So, my question is ... how did the unittest library figure out that it was supposed to run my decorated method?
The wrapper function's __name__ might be wrapper, but it's still TestAdd.test_add. As in, if you look at the TestAdd class's __dict__, you'll find the wrapper function bound to key 'test_add', and if you wanted to call the method, you would use the name test_add, not wrapper.
When unittest uses method names to determine whether a method is a test, it doesn't look at the __name__. It looks at what attribute name the method is associated with, and the decorator doesn't affect that.
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