--- layout: post status: publish published: true title: ! 'Python/Unittest : assertRaises raises Error' author: Julien Lengrand-Lambert author_login: jlengrand author_email: julien@lengrand.fr author_url: http://www.lengrand.fr wordpress_id: 327 wordpress_url: http://www.lengrand.fr/?p=327 date: 2011-12-02 13:49:49.000000000 +01:00 categories: - Python tags: - tippy - unittest - unit tests - agile - TDD - test driven development comments: - id: 828 author: md author_email: md@pmcd-cons.com author_url: '' date: !binary |- MjAxMi0wNC0xOSAyMTo1MzowNSArMDIwMA== date_gmt: !binary |- MjAxMi0wNC0xOSAyMDo1MzowNSArMDIwMA== content: ! "test_square_vlaue gives an eroror because assertRaises wants for 2nd arg a callable not a function call.\r\nthis should do:\r\nself.assertRaises(TypeError, df.square_value, 'A')" - id: 873 author: Julien Lengrand-Lambert author_email: julien@lengrand.fr author_url: http://www.lengrand.fr date: !binary |- MjAxMi0wNC0yNCAxMjo0MToyNCArMDIwMA== date_gmt: !binary |- MjAxMi0wNC0yNCAxMTo0MToyNCArMDIwMA== content: ! "Thanks for the info, I'll try this way of doing next time. \r\nIt is prettier than my current solution :)" --- Hi all, Today, a small hint about unit tests in Python I discovered while working on Tippy. In order to get as reliable code as possible, I am currently experiencing Agile techniques, and especially TDD. I develop Tippy in Python, and test methods with the excellent unittest framework.One of (in my mind at least) the most important tips Agile provides is the "fail fast" rule. And to fit with this rule, all my methods check their inputs before performing anything else. It implies a lot of assertRaises assertions in my tests. Here is an example of how it could be used : Let's say I want to create a (dum) function calculating the square value of a number. I will have to test that the input can really be multiplied. {% highlight python %} def square_value(a): """ Returns the square value of a. """ try: out = a*a except TypeError: raise TypeError("Input should be a string:") return out {% endhighlight %} {% highlight python %} import dum_function as df # import function module import unittest class Test(unittest.TestCase): """ The class inherits from unittest """ def setUp(self): """ This method is called before each test """ self.false_int = "A" def tearDown(self): """ This method is called after each test """ pass #--- ## TESTS def test_square_value(self): # assertRaises(excClass, callableObj) prototype self.assertRaises(TypeError, df.square_value(self.false_int)) if __name__ == "__main__": unittest.main() {% endhighlight %} {% highlight python %} ====================================================================== ERROR: test_square_value (__main__.Test) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_dum_function.py", line 22, in test_square_value self.assertRaises(TypeError, df.square_value(self.false_int)) File "/home/jlengrand/Desktop/function.py", line 8, in square_value raise TypeError("Input should be a string:") TypeError: Input should be a string: ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (errors=1) {% endhighlight %} The TypeError is actullay raised, and generates a test failure. The problem is that this is exactly the behavior we wanted :s. To avoid this error, simply run the function using lambda in the test call : {% highlight python %} self.assertRaises(TypeError, lambda: df.square_value(self.false_int)) {% endhighlight %} The final output : {% highlight python %} ---------------------------------------------------------------------- Ran 1 test in 0.000s OK {% endhighlight %} Perfect ! Note : For the purpose of this article, I did not work "backwards" (created test before the function). I think this would have been counter productive for the effect I wanted to highlight.