Pythonのテストについて
Pythonのテストフレームワークである
unittest
、 doctest
、 nose
ライブラリについてまとめます。
unittestによるテスト
標準ライブラリには2つテストフレームがあり、 unittest
ライブラリはその1つです。
以下に、 unittest
を使用したサンプルコードを記述します。
cap.py
にテスト対象のメソッドを記述し、
test_cap.py
でテストを実行します。
def convert_to_title_case(text):
# 文字列内の単語の先頭をすべて大文字にする
return text.title()
import unittest
import cap
class TestCap(unittest.TestCase):
def setUp(self):
print('setUp()メソッドが呼び出されました')
def tearDown(self):
print('tearDown()メソッドが呼び出されました')
def test_one_word(self):
text = 'python'
result = cap.convert_to_title_case(text)
self.assertEqual(result, 'Python')
def test_multiple_word(self):
text = 'python programming'
result = cap.convert_to_title_case(text)
self.assertEqual(result, 'Python Programming')
if __name__ == "__main__":
unittest.main()
$ python learn-test/test_cap.py
setUp()メソッドが呼び出されました
tearDown()メソッドが呼び出されました
.setUp()メソッドが呼び出されました
tearDown()メソッドが呼び出されました
.
----------------------------------------------------------------------
Ran 2 tests in 0.003s
OK
setUp()メソッドとtearDown()メソッドについて
setUp()
と tearDown()
の目的は、
テストが必要とする外部リソースを確保・解放することです。
ここでの外部リソースは、例えばデータベース接続や、なんらかのテストデータのことで、
テストを実行する前後になんらかの処理を行いたい場合に有用です。
しかし、 unittestライブライリの setUp()
と tearDown()
はクラス単位で作成するものの、テストごとに実行されます。
ちなみに、Python3.2以降では、setUpClassやtearDownClass、setUpModuleやtesrDownModuleが追加され、
これらを使用すれば、クラスやモジュールレベルで実行できるようになります。
doctestによるテスト
標準ライブラリに含まれている doctest
パッケージを使用すれば、
docstring(クラスや関数内に記述するコメント)の中にテストを書くことができます。
以下、テストが失敗する場合と成功場合のコードを書いて挙動を確認します。
テストが失敗する場合
def convert_to_title_case(text):
'''
>>> convert_to_title_case('python')
'Python'
>>> convert_to_title_case('Python Programming')
Error
'''
return text.title()
if __name__ == "__main__":
import doctest
doctest.testmod()
$ python test_cap_with_docstring.py
**********************************************************************
File "test_cap_with_docstring.py", line 5, in __main__.convert_to_title_case
Failed example:
convert_to_title_case('Python Programming')
Expected:
Error
Got:
'Python Programming'
**********************************************************************
1 items had failures:
1 of 2 in __main__.convert_to_title_case
***Test Failed*** 1 failures.
テストが成功する場合
def convert_to_title_case(text):
'''
>>> convert_to_title_case('python')
'Python'
>>> convert_to_title_case('python programming')
'Python Programming'
'''
return text.title()
if __name__ == "__main__":
import doctest
doctest.testmod()
$ python test_success_cap_with_docstring.py
$
すべてのテストが成功した場合は、何も表示されません。
詳細を確認する場合は -v
オプションをつけると確認できます。
$python test_success_cap_with_docstring.py -v
Trying:
convert_to_title_case('python')
Expecting:
'Python'
ok
Trying:
convert_to_title_case('python programming')
Expecting:
'Python Programming'
ok
1 items had no tests:
__main__
1 items passed all tests:
2 tests in __main__.convert_to_title_case
2 tests in 2 items.
2 passed and 0 failed.
Test passed.
nose
ライブライリ使用したテスト
nose
はPythonのサードパーティーのテストフレームワークの1つです。
まずはインストールします。
$ pip install nose
nose
で使用するメソッドを一部紹介して、サンプルコードを記述します。
メソッドのリファレンスはこちら
-
nose.tools.ok_(expr, msg=None)
:expr
がTrueかどうか評価します。 -
nose.tools.wq_(a, b,, msg=None)
:a
とb
が等価(==
)であるか評価します。 -
nose.tools.times(limit)
:メソッドにデコレータとして付与し、limit
で指定した時間内にテストが実行されるかどうか評価します。 -
nose.tools.with_setup(setup=None, teardown=None)
:デコレータとして、 メソッドレベルでsetup
とteardown
の仕組みを実行します。
import cap
from nose.tools import eq_, with_setup
def setUp():
print('setUp()メソッドが呼び出されました')
def tearDown():
print('tearDown()メソッドが呼び出されました')
def set_ok():
print('set_ok()メソッドが呼びだれました。')
@with_setup(set_ok)
def test_one_work():
text = 'python'
result = cap.convert_to_title_case(text)
eq_(result, 'Python')
def test_multiple_word():
text = 'python programming'
result = cap.convert_to_title_case(text)
eq_(result, 'Python Programming')
nose をインストールすると、 nosetests
コマンドが使用できるようになります
$ nosetests -s -v nose_test_sample.py
setUp()メソッドが呼び出されました
nose_test_sample.test_one_work ... setUp()メソッドが呼び出されました
tearDown()メソッドが呼び出されました
ok
nose_test_sample.test_multiple_word ... ok
tearDown()メソッドが呼び出されました
----------------------------------------------------------------------
Ran 2 tests in 0.024s
OK
setup()
、 teardown()
によってモジュールレベルで setUp
/ tearDown
の仕組みを適用します。
ちなみに、パッケージレベルになると、 __init__.py
モジュールの中に setUp
/ tearDown
関数に書く必要があります。
unittest
と nose
のそれぞれの特徴
最後に unittest
と nose
の特徴を列挙します。
unitest
- PEP8に従っていない
- JUnitに似せられた
-
TestCase
を必ず継承しないといけない。 - setUp/tearDownの仕組むがクラス単位に縛られるのにも関わらず、メソッドごとに実行
nose
- 継承が不要等、簡単にテストが書ける
- プラグインが豊富
- PEP8に従っている