Reputation: 2260
I'm not sure what's the best way to build independent unit tests on methods of a python class. Here is a trivial example:
class MyClass(object):
def __init__(self, data):
self.data = data
def myMethod(self):
#do something
return True
I'm building unit tests like this:
class TestMyClass(unittest.TestCase):
def test_init(self):
mydata = mock.Mock()
c = MyClass(mydata)
self.assertEqual(c.data, mydata)
def test_myMethod(self):
mydata = mock.Mock()
c = MyClass(mydata)
self.assertTrue(c.myMethod())
OK, this is very trivial... but the point is: test_myMethod()
depends on __init__
because I have to instantiate the object itself: it isn't really isolated. The only way that has come to my mind to solve this issue is mocking the object itself... but how can I test a real method on a mocked object?
I know that in real world a perfect isolation could be impossible, but I'm curious to know if there are better ways.
Upvotes: 0
Views: 337
Reputation: 522510
It comes down to what you want to test and in how much granularity. For example, what exactly is the assertion that c.data
equals the data you have just assigned in the previous line actually test? It tests a single line of practical code, and it tests a rather unimportant implementation detail. This is probably much too granular to bother.
You want to ensure that your object behaves as it should overall. That means you want to test that you can instantiate it, and then assert that
Your tests should focus on object behaviour, not on testing implementation minutiae. Write your tests so you could drop in an alternative object implementing the same behaviour in a different way without breaking your tests. You are writing that class to get some specified tasks done; test that your implementation can get those tasks done, not how it gets them done.
Exempli gratia:
def test_worksWithDataA(self):
c = MyClass({'some': 'data'})
self.assertTrue(c.myMethod())
def test_worksWithDataB(self):
c = MyClass({'other': 'data'})
self.assertFalse(c.myMethod())
def test_rejectsDataC(self):
with self.assertRaises(SomeException):
MyClass(None)
You only need to mock something if you need to pass a dependency, but that dependency is too complex to instantiate for the sake of the test. As long as your data is just a dict
, there's no need to mock it. If your data is a complex type on its own, then you may want to mock it in order to test MyClass
, without getting tangled up in having to test that other class at the same time. When mocking, again, mock the expected behaviour of that class; as a rule of thumb, all the behaviour you're asserting your class has using unit tests can be mocked elsewhere.
Upvotes: 4