今川館

都内勤務の地味OLです

pythonのunittestで例外の送出を検証する場合はassertRaises

pythonのunittest.TestCaseで例外の送出を検証したいときは

  • TestCase.assertRaises
  • TestCase.failUnlessRaises

でやる。
試しに上記メソッドで検証した場合と独自にそれっぽい検証メソッドを定義した場合を比較してみる。

# -*- coding:utf-8 -*-

import unittest

class TheTest(unittest.TestCase):
    def checkRaise(self, fn, ex_clz):
        try:
            fn()
        except Exception, ex:
            self.assertEquals(ex_clz, ex.__class__, '期待(%s)と違う例外が送出されています %s: %s' % (ex_clz.__name__, ex.__class__.__name__, ex))
        else:
            self.fail('期待した例外が送出されませんでした')

    def test_foo(self):
        self.checkRaise(lambda: [][0], IndexError)
    
    def test_bar(self):
        self.checkRaise(lambda: [][0], ValueError)
        
    def test_baz(self):
        self.checkRaise(lambda: True, IndexError)

class SimpleNaTest(unittest.TestCase):
    def test_hoge(self):
        self.assertRaises(IndexError, lambda: [][0])

    def test_fuga(self):
        self.assertRaises(ValueError, lambda: [][0])

    def test_piyo(self):
        self.assertRaises(IndexError, lambda: True)


def main(*args):
    unittest.main()

if __name__ == '__main__':
    import sys
    main(sys.argv[1:])

実行結果は以下の通り。

E.FFF.
======================================================================
ERROR: test_fuga (__main__.SimpleNaTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "baz.py", line 28, in test_fuga
    self.assertRaises(ValueError, lambda: [][0])
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 336, in failUnlessRaises
    callableObj(*args, **kwargs)
  File "baz.py", line 28, in <lambda>
    self.assertRaises(ValueError, lambda: [][0])
IndexError: list index out of range

======================================================================
FAIL: test_piyo (__main__.SimpleNaTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "baz.py", line 31, in test_piyo
    self.assertRaises(IndexError, lambda: True)
AssertionError: IndexError not raised

======================================================================
FAIL: test_bar (__main__.TheTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "baz.py", line 18, in test_bar
    self.checkRaise(lambda: [][0], ValueError)
  File "baz.py", line 10, in checkRaise
    self.assertEquals(ex_clz, ex.__class__, '期待(%s)と違う例外が送出されています %s: %s' % (ex_clz.__name__, ex.__class__.__name__, ex))
AssertionError: 期待(ValueError)と違う例外が送出されています IndexError: list index out of range

======================================================================
FAIL: test_baz (__main__.TheTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "baz.py", line 21, in test_baz
    self.checkRaise(lambda: True, IndexError)
  File "baz.py", line 12, in checkRaise
    self.fail('期待した例外が送出されませんでした')
AssertionError: 期待した例外が送出されませんでした

----------------------------------------------------------------------
Ran 6 tests in 0.001s

FAILED (failures=3, errors=1)

SimpleNaTest.test_fugaがFailでなくErrorになるが、あまり気にする必要はないと思う。
(どっちでもどうせテストが通らないから)
ちなみに、assertRaises, assertUnlessRaisesで期待される例外が複数ある場合は例外のタプルを渡すらしい。

self.assertRaises((ValueError, IndexError), lambda: [][0])

こんな風に。
参考: http://www.python.jp/doc/2.6/library/unittest.html#unittest.TestCase.assertRaises