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.
Related
I use unittest in my testing. I import a class in yhab.main package as...
from yhab.blah import SomeClass
def some_func():
some_instance = SomeClass()
return some_instance.method()
yhab.blah.SomeClass is defined as...
class SomeClass:
def method(self):
return 'hello'
And then I write a test like this...
#mock.patch('yhab.blah.SomeClass')
def test_mock_of_blah_someclass(mock_some_class):
assert some_func() != 'hello'
the invocation of method() calls the real instance, not a mock.
But if I do this...
#mock.patch('yhab.main.SomeClass')
def test_mock_of_main_someclass(mock_some_class):
assert some_func() != 'hello'
the invocation of method() calls the mock, not the real instance and the test passes.
Why is that?
I was thinking that python must make some sort of copy of the class definition when an import happens, but I wrote a test that proves that to not be the case.
The docs say the following, which kind of eludes to this, but it doesn't really say it outright, and IMO doesn't really explain it, especially for a python newb...
Patching a class replaces the class with a MagicMock instance. If the
class is instantiated in the code under test then it will be the
return_value of the mock that will be used.
Do the docs need to be updated to be clear?
After you import SomeClass from yhab.blah, it ends up in the yhab.main namespace, not in the yhab.blah namespace.
Try to use #mock.patch('yhab.main.SomeClass') instead of #mock.patch('yhab.blah.SomeClass').
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
I am trying to get a hang of mocking objects, and seem to by confused by something very basic. I am trying to mock object MyClass and then unit test one of its methods. here is my code:
import mock
import unittest
class MyClass(object):
def __init__(self, a):
self.a = a
def add_two(self):
return self.a + 2
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
m_my_class = mock.Mock()
m_my_class.a = 10
result = m_my_class.add_two() # I would expect the result to be 12
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
if __name__ == '__main__':
unittest.main()
In m_my_class.a = 10 I set value of a to to and then in m_my_class.add_two() I add a two, shouldn't I get 12? However, result is:
16 import ipdb;ipdb.set_trace()
---> 17 self.assert_equal(result, 12)
18
ipdb> result
<Mock name='mock.add_two()' id='18379792'>
What am I missing?
Since I am passing the location of the class via decorator to the test method #mock.patch('__main__.MyClass'), shouldn't mocked have all the methods? Because if not, then why does it matter what class we include in the decorator?
Edit:
When I run this code, I still get the same thing.
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
dummy_mock.a = 10
result = dummy_mock.add_two()
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
Result:
ipdb> result
<MagicMock name='MyClass.add_two()' id='38647312'>
Patching the class is almost certainly not what you want to do here. For example, if you changed your test method to this:
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
m_my_class = MyClass(5)
print m_my_class
You will find that rather than getting what you expect:
<__main__.MyClass object at 0x0000000002C53E48>
You'll get this:
<MagicMock name='MyClass()' id='46477888'>
Patching the class in the method means that any time within the method that something tries to instantiate the class it will instead get a mock object. In your particular case, calling MyClass(5) will return the same mock object as calling dummy_mock would. This allows you to set up the mock object so that when you go to test your code the mock object will behave as you want it to.
You really would only use this for dependencies, not the class you are testing. So for example, if your class retrieved data from SQL, you'd patch the SQL class to give your class a mock instead of the normal SQL connection. This allows you to test a class in isolation, without having to worry about externals (like the SQL) getting in the way.
In your example though, you seem to be trying to test a method in isolation. A way you could do that is to extract the function from the method and use that. In code:
def test_add_two(self):
test_mock = mock.Mock()
test_mock.add_two = MyClass.add_two.__func__
test_mock.a = 10
result = test_mock.add_two(test_mock)
self.assert_equal(result, 12)
Normally you wouldn't have to pass in an argument for the self argument, but as here we've pulled out the function you do need to pass in the self argument. If you want you can turn the function into a method bound to your mock object, like this:
import types
...
test_mock.add_two = types.MethodType(MyClass.add_two.__func__, test_mock, test_mock.__class__)
result = test_mock.add_two()
If the function you are testing calls any other methods, you'll need to either do this or mock it out for each of the methods.
I would advise against using this strategy too much, in part because of needing to take care of methods that the tested method calls. Of course, being able to mock out the methods it depends on may be exactly what you're trying to do. In any case, it requires the unit tests to have a pretty deep understanding of how the method works, and not just of what it is supposed to produce. That makes the test very fragile, making it so that you are likely to see the test break far more often than the method you are testing.
Why are you mocking your SUT? This is generally something that you should avoid doing because it introduces the risk that you will not be testing what you think you're testing.
The point of a unit test is to verify the behavior of a unit in complete isolation. One unit typically collaborates with other units in order to provide some useful functionality. Test doubles (mocks, fakes, etc.) are the tools used to achieve this isolation. In a unit test, collaborators of the SUT are replaced with test doubles in order to minimize the number of moving parts.
Your SUT, MyClass, doesn't appear to have any collaborators. As such, no test doubles are necessary to test this unit in isolation (it's already self-contained). This allows you to greatly simplify your unit test:
import mock
import unittest
class MyClass(object):
def __init__(self, a):
self.a = a
def add_two(self):
return self.a + 2
class TestMyClass(unittest.TestCase):
def test_add_two(self):
m_my_class = MyClass()
m_my_class.a = 10
result = m_my_class.add_two() # I would expect the result to be 12
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
if __name__ == '__main__':
unittest.main()
Edit: The following code demonstrates how a mock object might be used. (Disclaimer: I don't normally work in Python, so my code is probably not very idiomatic. Hopefully the core point still makes sense, though.)
In this example, MyClass adds a value provided by a collaborator, instead of a hardcore value (2).
import mock
import unittest
class MyClass(object):
def __init__(self, a, get_value):
self.a = a
self.get_value = get_value
def add_value(self):
return self.a + self.get_value()
class TestMyClass(unittest.TestCase):
def test_add_value(self):
m_test_value = 42
m_test_a = 10
m_my_class = MyClass()
m_get_test_value = mock.Mock(return_value=m_test_value)
m_my_class.a = test_a
result = m_my_class.add_value()
import ipdb;ipdb.set_trace()
self.assert_equal(result, m_test_a + m_test_value)
if __name__ == '__main__':
unittest.main()
The above example uses a mock object, instead of patching a class. Here is a pretty good explanation of the difference:
Mocking a class: Mock() or patch()?
I'm trying to set up some automatic unit testing for a project. I have some functions which, as a side effect occasionally call another function. I want to write a unit test which tests that the second function gets called but I'm stumped. Below is pseudocode example:
def a(self):
data = self.get()
if len(data) > 3500:
self.b()
# Bunch of other magic, which is easy to test.
def b(self):
serial.write("\x00\x01\x02")
How do I test that b()-gets called?
You can mock the function b using mock module and check if it was called. Here's an example:
import unittest
from mock import patch
def a(n):
if n > 10:
b()
def b():
print "test"
class MyTestCase(unittest.TestCase):
#patch('__main__.b')
def test_b_called(self, mock):
a(11)
self.assertTrue(mock.called)
#patch('__main__.b')
def test_b_not_called(self, mock):
a(10)
self.assertFalse(mock.called)
if __name__ == "__main__":
unittest.main()
Also see:
Assert that a method was called in a Python unit test
Mocking a class: Mock() or patch()?
Hope that helps.
Various solutions are possible for this thing. But first, I have to point out that unit testing is meant for testing units; what a unit is can be a matter of viewing things. In your case I'd say a unit is the function a() because you would like to test that your unit behaves correctly, meaning it calls function b() at the right spot. A different view would be to say that functions a() and b() are a unit. Then you do not like to check whether function b() gets called, you just want to test the result of the call of function a(). So make up your mind which suits your case best.
In case you really want to test function a() as a unit, you should prepare your unit to being tested. In your case that could be done by adding to it an additional argument (which defaults to function b) and which will be used instead of the hard-coded function b() call in a():
def a(self, subfunction=None):
is subfunction is None: # for testing
subfunction = self.b
data = self.get()
if len(data) > 3500:
subfunction()
Now you can inject (during testing) a helper function which just informs the test that it got called:
store = None
def injected(*args, **kwargs):
global store
store = args, kwargs
obj.a(subfunction=injected)
# now check if global store is set properly
I am doing some unittests with python and some pre-test checks in setUpClass. How can I throw a unitest-fail within the setUpClass, as the following simple example:
class MyTests(unittest.TestCase):
#classmethod
def setUpClass(cls):
unittest.TestCase.fail("Test")
def test1(self):
pass
if __name__ == '__main__':
unittest.main()
gives the error TypeError: unbound method fail() must be called with TestCase instance as first argument (got str instance instead).
I understand the error I get as fail is a instance method, and I don't have an instance of MyClass yet. Using an instance on-the-fly like
unittest.TestCase().fail("Test")
also does not work, as unittest.TestCase itself has no tests. Any ideas how to fail all tests in MyClass, when some condition in setUpClass is not met?
Followup question: Is there a way to see the tests in setUpClass?
self.fail("test") put into your setUp instance method fails all the tests
I think the easiest way to do this at the class level is to make a class variable so something like:
#classmethod
def setUpClass(cls):
cls.flag = False
def setUp(self):
if self.flag:
self.fail("conditions not met")
Hope this is what you want.
Using a simple assert should work
assert False, "I mean for this to fail"
I'm not an expert in python but with same problem, I've resolved adding cls param:
...
#classmethod
def setUpClass(cls):
cls.fail(cls, "Test")
...
I think is strange but clearer.
When you pass cls, warning appear (Expected type 'TestCase', got 'Type[MyTests]' instead) and MyTests inherits from TestCase thus can
ignoring adding: # noinspection PyTypeChecker