最近、他の言語で単体テスト自動化するために色々調べてみて単体テストツールについて興味を持つようになりました。
そこで今勉強しているPythonの単体テスト事情について調べてみたところ、Pythonでの単体テストフレームワークの主流は、unittestとpytestが良く使われているみたいです。
今回はその中でもPythonの標準ライブラリとして提供されているunittestがどんなものか試してみました。
unittestモジュール
基本構文
unittestモジュールは、Pythonの標準ライブラリとして提供されている単体テスト用のモジュールです。以下の構文にもある通りPythonに最初から同梱されているモジュールなのでimportすれば使えるようになります。
import unittest
class Testクラス(unittest.TestCase):
def test_メソッド(self):
self.assertEqual(期待値、検査値)
unittest.TestCaseクラスを継承した単体テストクラスを作成し、単体テストのメソッドを作成していきます。
よく使用するテストメソッド
unittestでよく使う代表的なメソッドは以下の通りです。
テスト結果が想定と違っていた場合はAssertionErrorが発生します。
メソッド | テスト内容 |
---|---|
assertEqual(a,b) | aとbが等しければOK |
assertNotEqual(a,b) | aとbが等しくなければOK |
assertTrue(x) | xがTrueならOK |
assertFalse(x) | xがFalseならOK |
assertIs(a,b) | aとbが同じオブジェクトであればOK |
assertIsNot(a,b) | aとbが同じオブジェクトでなければOK |
assertIsNone(x) | xがNoneであればOK |
assertIsNotNone(x) | xがNoneでなければOK |
assertIn(a,b) | aがbに含まれていればOK |
assertNotIn(a,b) | aがbに含まれていなければOK |
assertIsInstance(a,b) | aがbのインスタンスであればOK |
assertNotIsInstance(a,b) | aがbのインスタンスでなければOK |
単体テスト実行コマンド
単体テストを実装して実行するときは以下のコマンドを実行します。
python -m unittest test_テスト対象モジュール.py
-mはモジュールを実行する意味でここではunittestモジュールを実行するという意味です。
テストモジュールは、ディスカバリというtest_*.pyというファイルを検索して自動で実行してくれ る機能があるので必ずtest_という名前で作成するようにしましょう。
unittestを実装してみる
テストされる側のプログラム
実際にunittestを実装してみます。今回はunittestでテストされる側のモジュールとしてcalculation.pyというファイルを作成して以下の関数をサンプルとして作成してみました。
#テストされる側のプログラム
#二つの値を足し算
def addtion_num(num1,num2):
return num1 + num2
#二つの値を掛け算
def multiplication_num(num1,num2):
return num1 * num2
#正の整数判定
def ispositive_int(num):
return num > 0
テストプログラム
上記3つの関数をテストするプログラムは以下の通りです。
import unittest
import calculation
class TestCalcFuncs(unittest.TestCase):
"""
addtion_numの単体テスト(足し算)
"""
def test_addtion_num(self):
self.assertEqual(5,calculation.addtion_num(2,3))
"""
multiplication_numの単体テスト(掛け算)
"""
def test_multiplication_num(self):
self.assertEqual(6,calculation.multiplication_num(2,3))
"""
ispositive_intの単体テスト(正の整数判定)
"""
def test_ispositive_int(self):
self.assertTrue(calculation.ispositive_int(2))
self.assertFalse(calculation.ispositive_int(-1))
self.assertFalse(calculation.ispositive_int(0))
- ファイル名は、test_形式にする。
- 関数名もtest_形式にする。
- import unittestでunittestモジュールをインポートする。
- import calculationでテストされる側のモジュールをインポートする。
単体テストの実行
単体テストの実行は、ターミナルなどでunittestモジュールを-mオプションで指定して引数にテストモジュールを指定します。今回のファイル構成では以下のようになります。
python -m unittest test_calculation.py
上述にもある通り、Pythonのunittestはディスカバリという仕組みがあるのでpython -m unittestだけでもテストプログラムが実行されます。
すべてのテストがOKだったときの実行結果です。
(実行結果) ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK
試しに掛け算のプログラムの期待値をわざと違うものにして実行すると以下のようになります。
(掛け算プログラムの期待値を本来の6→5に変更して実行)
(実行結果)
FAIL: test_multiplication_num (test_calculation.TestCalcFuncs)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\python\py\test_calculation.py", line 15, in test_multiplication_num
self.assertEqual(5,calculation.multiplication_num(2,3))
AssertionError: 5 != 6
----------------------------------------------------------------------
Ran 3 tests in 0.002s
FAILED (failures=1)
AssertionErrorが発生して期待値は5なのに検査値が6で一致していない旨のエラーが出ています。
こんな感じで単体テストを実装しておくと、想定していた処理結果が違うとエラーになるので不具合などがすぐにわかって品質向上が見込めます。
まとめ
- unittestはPythonの標準ライブラリなのでimportだけで使える
- テストされる側のモジュールもテストプログラム内にimportする
- unittestはほとんどの場合assert(アサーション)メソッドを使う
- ファイル名や関数名はtest_形式のネーミングルールで実装する
- ユニットテストを実装することで品質向上が見込める
今回はPython標準のunittestについてでしたが、pythonには他にもpytestという単体テストフレームワークが存在します。pytestも評判がいいみたいなので機会があれば試してみたいと思います。
コメント