mirror of
https://github.com/jlengrand/jlengrand.github.io.git
synced 2026-03-10 08:31:22 +00:00
141 lines
5.0 KiB
Markdown
141 lines
5.0 KiB
Markdown
---
|
||
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 <strong>unit tests</strong> in Python I discovered while working on <strong><a title="tippy on github" href="https://github.com/jlengrand/Tippy" target="_blank">Tippy</a></strong>.
|
||
|
||
In order to get as reliable code as possible, I am currently experiencing <strong><a title="agile" href="http://en.wikipedia.org/wiki/Agile_software_development" target="_blank">Agile</a></strong> techniques, and especially <strong><a title="TDD" href="http://fr.wikipedia.org/wiki/Test_Driven_Development" target="_blank">TDD</a></strong>. I develop <strong>Tippy</strong> in Python, and test methods with the excellent <a title="unittest framework" href="http://docs.python.org/library/unittest.html" target="_blank">unittest</a> framework.One of (in my mind at least) the most important tips Agile provides is the "<a title="fail fast" href="http://en.wikipedia.org/wiki/Fail-fast" target="_blank">fail fast</a>" rule. And to fit with this rule, all my methods check their inputs before performing anything else.
|
||
|
||
It implies a lot of <strong>assertRaises</strong> 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.
|
||
<ul>
|
||
<li>First, here is the corresponding (still dum :p) function in file dum_function.py :</li>
|
||
</ul>
|
||
{% 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 %}
|
||
<ul>
|
||
<li>Here is the test to be performed (only this test is inserted):</li>
|
||
</ul>
|
||
{% 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 %}
|
||
<ul>
|
||
<li>We are now ready to test our function! Here is what happens when trying to run the test :</li>
|
||
</ul>
|
||
{% 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 <strong>TypeError</strong> is actullay raised, and generates a test failure. The problem is that this is <strong>exactly the behavior</strong> 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 !
|
||
|
||
<em><strong>Note :</strong> 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.</em>
|