概要
unittestモジュールを使用して単体テストを作成/実施する方法についてまとめた。
unittestモジュールのポイント
・unittest.TestCaseを継承してクラスを作成する
・慣習として「Test」をクラスの頭につける
・慣習として「test_」を関数の頭につける
・テストコードにて「実行結果」と「想定結果」を比較する
unittestモジュールの使い方
テスト対象の関数用意
まずはテスト対象の関数が存在すること。
# テスト対象の関数
def culc_multi(a, b):
""" aとbを乗算した結果を返却 """
return a * b
テストケースを作成
unittestモジュールをインポートして、テストケースを作成する。
import unittest
# テスト対象の関数
def culc_multi(a, b):
""" aとbを乗算した結果を返却 """
return a * b
# テストクラス
class TestCulcAdd(unittest.TestCase):
# テストケース
def test_culc_add(self):
""" 関数culc_multiが2つの引数の乗算を返すか確認. """
self.assertEqual(culc_multi(3, 9), 27)
テスト実行方法
テスト実行方法については様々存在する。
基本的にはunittest.main()を呼び出して実行するが、jupyter labの場合は多少異なる。
jupyter labにてテストを実行する方法
jupyter labにてunittest.main()を実行するとAttributeErrorが発生する。
以下のように記述すると、テストを実行できる。
import unittest
# テスト対象の関数
def culc_multi(a, b):
""" aとbを乗算した結果を返却 """
return a * b
# テストクラス
class TestCulcAdd(unittest.TestCase):
def test_culc_add(self):
""" 関数culc_multiが2つの引数の乗算を返すか確認. """
self.assertEqual(culc_multi(3, 9), 27)
if __name__ == '__main__':
#unittest.main() # AttributeError: module '__main__' has no attribute・・・というエラー
unittest.main(argv=['first-arg-is-ignored'], exit=False)
#----------------------------------------------------------------------
# 出力
#Ran 1 test in 0.002s
#
#OK
テストの実行時間と実行結果OKが出力される。
【if __name__(略)】の書き方が不明な場合、直接【unittest.main(argv=[‘first-arg-is-ignored’], exit=False)】と記述しても実行は可能。
Pythonファイルにてテストを実行する方法
jupyter labを使用している場合、以下の手順でPythonファイルを作成する。
New Launcherの立ち上げ(Ctr+Shit+L)
main.py(名前はなんでもいい)として、コードを張り付ける
Pythonファイルにテスト対象の関数とテストコードを張り付ける。
尚、実行関数はunittest.main()とすること。
ターミナルからPythonファイルの実行
ターミナルを起動。
以下のコマンドを実行する。
ターミナル
python main.py(※main.pyの箇所は、作成したPythonファイル名)
Pythonファイルを指定して実行
Pythonファイルからunittest.main()の記述を削除。
import unittest
# テスト対象の関数
def culc_multi(a, b):
""" aとbを乗算した結果を返却 """
return a * b
# テストクラス
class TestCulcAdd(unittest.TestCase):
def test_culc_add(self):
""" 関数culc_multiが2つの引数の乗算を返すか確認. """
self.assertEqual(culc_multi(3, 9), 27)
ターミナルから以下を実行することで、Pythonファイルに記述されているすべてのテストメソッドを実行可能。
ターミナル
python -m unittest main.py
特定のテストメソッドのみ実行
特定のテストメソッドを実行には以下のように、【ファイル名.クラス名.テストメソッド名】を指定して実行する。
ターミナル
python -m unittest main.TestCulcAdd.test_culc_add
テストメソッド(assertXXX)の使い方
unittest.TestCaseクラスに、テスト対象の「実行結果」と「想定結果」を比較するテストメソッドが用意されている。
TestCaseを継承することで使用可能になる。
主なテストメソッドは以下。
種類 | 詳細 |
---|---|
assertEqual(a, b) | a == b |
assertNotEqual(a, b) | a != b |
assertTrue(x) | x == True |
assertFalse(x) | x == False |
以下はもともと存在するStringの関数をテストしたもの。
assert文は以下のように使用する。
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
""" str.upper()メソッドが大文字を返すか確認 """
self.assertEqual("test".upper(), "TEST")
def test_not_upper(self):
""" str.upper()メソッドがそのままの文字列を返さない確認 """
self.assertNotEqual("test".upper(), "test")
def test_isdigit(self):
""" str.isdigit()メソッドが正しく機能するか確認(True) """
self.assertTrue("543".isdigit())
def test_not_isdigit(self):
""" str.isdigit()メソッドが正しく機能するか確認(False) """
self.assertFalse("543a".isdigit())
def test_not_isdigit_2(self):
""" テスト結果を誤るケースその1 """
self.assertFalse("321".isdigit()) # AssertionError: True is not false
def test_upper_2(self):
""" テスト結果を誤るケースその2 """
self.assertEqual("test".upper(), "test") # AssertionError: 'TEST' != 'test'
if __name__ == "__main__":
unittest.main(argv=['first-arg-is-ignored'], exit=False)
#-----------------------------------------------
# 出力
#Ran 6 tests in 0.004s
#
#FAILED (failures=2) ※エラーの数
テスト結果が正しくない場合、「FAILED (failures=★)」と表示される。
※★⇒テストエラーの数
リストや辞書のテスト方法
リストや辞書も同様にassertEqualで比較可能。
import unittest
# Utilクラス
class CreateUtils:
@staticmethod
def create_nums(num):
""" 引数から始まる10個の数で終わるリストを返却 """
return list(range(num, num + 10))
@staticmethod
def create_dict(items):
""" リストで受け取った値をインデックスと紐づけた辞書にして返却 """
result_dict = {}
for i, val in enumerate(items, 1):
result_dict[i] = val
return result_dict
# Utilテストクラス
class TestCreateUtils(unittest.TestCase):
def test_create_nums(self):
""" create_numsが正しい結果を返却するか確認 """
expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
actual = CreateUtils.create_nums(1)
self.assertEqual(expected, actual)
def test_create_dict(self):
""" create_dictが正しい結果を返却するか確認 """
expected = {
1: "りんご",
2: "ごりら",
3: "らっぱ"
}
actual = CreateUtils.create_dict(["りんご", "ごりら", "らっぱ"])
self.assertEqual(expected, actual)
if __name__ == "__main__":
unittest.main(argv=['first-arg-is-ignored'], exit=False)
#----------------------------------------------------------------------
#Ran 2 tests in 0.004s
#OK
FizzBuzzのテスト
import unittest
def fizzbuzz(num):
if num % 15 == 0:
return "FizzBuzz"
elif num % 3 == 0:
return "Fizz"
elif num % 5 == 0:
return "Buzz"
else:
return str(num)
class TestFizzBuzz(unittest.TestCase):
def test_fizzbuzz_FizzBuzz(self):
""" 15の倍数のテスト """
self.assertEqual("FizzBuzz", fizzbuzz(90))
def test_fizzbuzz_Fizz(self):
""" 3の倍数のテスト """
self.assertEqual("Fizz", fizzbuzz(33))
def test_fizzbuzz_Buzz(self):
""" 5の倍数のテスト """
self.assertEqual("Buzz", fizzbuzz(50))
def test_fizzbuzz_other(self):
""" 3と5の倍数以外 """
self.assertEqual("98", fizzbuzz(98))
if __name__ == "__main__":
unittest.main(argv=['first-arg-is-ignored'], exit=False)
#------------------------------------------------------------
#Ran 4 tests in 0.002s
#OK