pythonのunittestメモ
unittest とは
pythonでユニットテストをするための標準モジュールのこと。
ちなみに、pythonで関数やクラスの挙動をテストする方法として、doctest モジュールもあるが、こちらは docstring を用いて記述するものであり、あまり複雑なテストは行えない。むしろ、具体的な使用方法などを記述する目的で使用する事が多い(気がする)。
基本的な使い方
unittestを使うシンプルな例(source)
import unittest # unittestをインポート # unittest.TestCaseを継承して、自作クラスを定義 class TestStringMethods(unittest.TestCase): def test_upper(self): self.assertEqual('foo'.upper(), 'FOO') # イコールかどうかを検証 def test_isupper(self): self.assertTrue('FOO'.isupper()) # Trueかどうかを検証 self.assertFalse('Foo'.isupper()) # Falseかどうかを検証 def test_split(self): s = 'hello world' self.assertEqual(s.split(), ['hello', 'world']) # s.splitのセパレータが非stringの場合を確認 with self.assertRaises(TypeError): s.split(2) if __name__ == '__main__': unittest.main()
テストコードを書く手順は、
unittest
をインポートunittest.TestCase
を継承したクラスを定義- クラスに、
test[任意]
メソッドを追加し、そこに検証するべきassert[任意]
を書く unittest.main()
を呼ぶ
注意
クラス名は任意でOKだが、メソッド名は 必ず test[任意]
にしなければならない。例 test_hoge, test_fuga
。
また、assert[任意]
はアサートメソッドであり、
例えば
a
とb
がイコールかどうかを検証したい場合assertEqual(a, b)
x
が True かどうかを検証したい場合assertTrue(x)
x
が False かどうかを検証したい場合assertFalse(x)
と書く。すべてのアサートメソッドは以下の通りである。
アサートメソッド | 確認事項 |
---|---|
assertEqual(a, b) | a == b |
assertNotEqual(a, b) | a != b |
assertTrue(x) | bool(x) is True |
assertFalse(x) | bool(x) is False |
assertIs(a, b) | a is b |
assertIsNot(a, b) | a is not b |
assertIsNone(x) | x is None |
assertIsNotNone(x) | x is not None |
assertIn(a, b) | a in b |
assertNotIn(a, b) | a not in b |
assertIsInstance(a, b) | isinstance(a, b) |
assertNotIsInstance(a, b) | not isinstance(a, b) |
上のアサートメソッドでは、変数や処理結果の 等価/非等価 や、真/偽を確認することはできるが、例外発生を確認することはできない(下記を参照)。
例外が発生することを確認したい
with assertRaises(予期される例外)
でチェックしたい処理を囲む。
import unittest class MyTest(unittest.TestCase): # 文字列と整数の加算演算はTypeErrorになる def test_type_error(self): with self.assertRaises(TypeError): 'string' + 1 if __name__ == '__main__': unittest.main()
複数の値を連続でテストしたい
繰り返し処理の中身でテストしたい場合のテストの書き方。サブテスト を利用する
例えば、2つのリストの中身が 順序も含めて 等しいかを確認したい場合。
ref_list = [1, 4, 3, 5, 7] ok_list = [1, 4, 3, 5, 7] ng_list = [1, 4, 5, 3, 7] # 3 と 5 が入れ替わってる
普通に比較するだけだと、TrueかFalseしかわからない
print(ref_list == ok_list) # True print(ref_list == ng_list) # False
サブテストを使って確認する
import unittest class ListTest(unittest.TestCase): # 実際の処理を行うメソッド def all_equal(self, msg, list_a, list_b): for a, b in zip(list_a, list_b): with self.subTest(msg, ref=a, target=b): self.assertEqual(a, b) # OKの場合のテスト def test_OK(self): ref_list = [1, 4, 3, 5, 7] ok_list = [1, 4, 3, 5, 7] return self.all_equal('たぶん OK', ref_list, ok_list) # NGのばあいのテスト def test_NG(self): ref_list = [1, 4, 3, 5, 7] ng_list = [1, 4, 5, 3, 7] # 3 と 5 が入れ替わってる return self.all_equal('たぶん NG', ref_list, ng_list) if __name__ == '__main__': unittest.main()
test_NG (__main__.ListTest) ... test_OK (__main__.ListTest) ... ok ====================================================================== FAIL: test_NG (__main__.ListTest) [たぶん NG] (ref=3, target=5) ---------------------------------------------------------------------- Traceback (most recent call last): File "e03.py", line 8, in all_equal self.assertEqual(a, b) AssertionError: 3 != 5 ====================================================================== FAIL: test_NG (__main__.ListTest) [たぶん NG] (ref=5, target=3) ---------------------------------------------------------------------- Traceback (most recent call last): File "e03.py", line 8, in all_equal self.assertEqual(a, b) AssertionError: 5 != 3 ---------------------------------------------------------------------- Ran 2 tests in 0.001s FAILED (failures=2)
3と5が入れ替わってることがわかる。失敗した回数も教えてくれる。
subTest
の引数は1つめにメッセージ、2つめ以降にサブテストが失敗した場合に表示したいものを入れる。 source