Unit testing is one of the most important parts of any project. TDD (test driven development) is a good habit to cultivate, in case you are not convinced, you don't know about TDD or you have never given it a try. I started using partial TDD recently, yes only partial for what I follow is that first I write a rough outline of the code, then I write tests and then I keep on re-factoring my code till all the tests are passing. Though there is a little flaw in this method according to me -- although writing tests are mostly trivial with those easy assert statements, sometimes you may write wrong tests which make you write wrong code too. So put more thought in writing tests than in writing code. Although many times you will agree with me that TDD is annoying, it does not let you do what you actually want to do (I mean the "way" you want to do it, the result may be same).
So in this post I am going to talk about mocks. What are mocks? There are some magical functions which do some abracadabra on your existing function and make them return anything that you want without actually even thinking what they are returning. Did I personify it a little too much? Let me explain in a little detail with the example of where I used mocking.
Unit tests should be independent of environment and any other module, so that each module can be developed separately without affecting the development of other modules. But many a times one module depends on others and in that case it gets messy to test those functions. In my case it was the "signature" rule which uses "gpg" utility to verify signature of messages. Here is a snippet of the code:
1from mailman.utilities.gpg import GPG
2
3@implementer(IRule)
4class Signature:
5 """Look for pgp-signature."""
6
7 name='signature'
8 description=_('The message has pgp-signature as application/pgp-signature part')
9 record = True
10 def __init__(self):
11 self._gpg = None
12
13 def check(self, mlist, msg, msgdata):
14 """See `IRule"""
15 gpg_dir = os.path.join(config.VAR_DIR, 'gpg')
16 self._gpg = GPG(gpg_dir)
So if you see in line 1 we import the GPG class from gpg utility. But when we write tests we don't want this function to "actually" create an instance of GPG class and "actually" verify the signature because it is not a function of signature rule and any errors or breakpoints in gpg utility may cause our tests for the "working" signature rule to fail. So what do we do? We mock and then we rock ;-). We mock the GPG instance created in signature rule to return "any specific value" irrespective of the input. See the code below:
1import mock
2
3class TestSignatureMime(unittest.TestCase):
4 """Test the signature handler."""
5
6 class Dummy_GPG_True:
7 def __init__(self, dir):
8 self._dir = dir
9
10 def verify_inline_signature(self, data):
11 return True
12
13 def verify_detached_signature(self, data):
14 return True
15
16
17 @mock.patch('mailman.rules.signature.GPG', new=Dummy_GPG_True)
18 def test_good_signature(self):
19 result = self._rule.check(self._mlist, self._msg, {})
20 self.assertTrue(result)