【Python】unittestの使い方まとめ

■概要

自分が作成した処理について、単体テストを実施するにあたり、unittestライブラリの使い方をまとめる。

▼試験対象のモジュール

今回、サンプルとして使用する試験対象のモジュールを以下に示す。

テスト対象の処理概要とサンプルコード

引数に設定された値が整数かチェックし、5倍にして返すクラス

・check_number.py

# 整数かチェックして5倍にするクラス
class CheckInputNumber(object):
    def check_input_number(self, number):
        if type(number) is not int:
            raise ValueError

        return number * 5

■unittestライブラリの使い方

・test_check_number.py

import unittest

import check_number

TEST_CASE = 'A'

class TestCheckInputNumber(unittest.TestCase):
    # 各テスト開始前処理
    def setUp(self):
        print(f'{"-"*5}テスト開始{"-"*5}')
        # テスト対象クラスのインスタンス
        self.test_target = check_number.CheckInputNumber()
    
    # 各テスト終了後処理
    def tearDown(self):
        # インスタンスの削除
        del self.test_target
        print(f'{"-"*5}テスト終了{"-"*5}')

    # 入力値と期待値が一致しているか確認
    def test_check_input_number(self):
        print(f'{"-"*3}値の確認テスト{"-"*3}')
        
        
        # 成功例
        self.assertEqual(self.test_target.check_input_number(4), 20)
        
        # 失敗例
        # self.assertEqual(self.test_target.check_input_number(4), 10)

    # 例外処理が想定通り動くか確認
    def test_check_input_number_raise(self):
        print(f'{"-"*3}例外の確認テスト{"-"*3}')
        with self.assertRaises(ValueError):
            # 成功例
            self.assertEqual(self.test_target.check_input_number('1'), '5')

            # 失敗例
            # self.assertEqual(self.test_target.check_input_number(1), 5)
    
    # テストをスキップ
    @unittest.skip('skip def')
    def test_check_input_number_skip(self):
        print(f'{"-"*3}確認テスト:skip{"-"*3}')
    
    # 条件が合致すれば、テストをスキップ
    @unittest.skipIf(TEST_CASE=='A', 'skip A case')
    def test_check_input_number_skip_if(self):
        print(f'{"-"*3}確認テスト:skip if{"-"*3}')


if __name__ == '__main__':
    unittest.main()

▼setUpメソッド

各テスト開始前に呼び出されるメソッド

事前にテスト対象のクラスをインスタンスしておけば、各テストメソッドでインスタンスする必要なし。

def setUp(self):
    # テスト対象クラスをインスタンスする。

▼tearDownメソッド

各テスト終了後に呼び出されるメソッド。

テスト対象のクラスをインスタンスを削除する際に使用すれば、各テストメソッドで実行する必要なし。

def tearDown(self):
    # テスト対象クラスのインスタンスを削除

▼テストスキップのデコレータ

テストをスキッしたい場合は、以下のデコレータを使用する。

@unittest.skip('<reason>')
def test_case():

条件が合致すれば、テストをスキップしたい場合は、以下のデコレータを使用する。

TEST_CASE == 'A'

@unittest.skipIf(TEST_CASE=='A', '<reason>')
def test_case():

▼assertEqualメソッド

入力値と期待値が一致していればOK、一致していなければNGを返す。

# self.assertEqual(<入力値>, <期待値>)
self.assertEqual(self.test_target.check_input_number(1), 5)

▼assertRaisesメソッド

例外処理が想定通り実行されるか確認するメソッド。
with句で括る。

with self.assertRaises(<期待する例外:ValueErrorなど>):
    # assertEqualメソッドなどの検証を書く

■実行結果

▼想定通りOKパターン

$ python3 test_check_number.py 
-----テスト開始-----
---値の確認テスト---
-----テスト終了-----
.-----テスト開始-----
---例外の確認テスト---
-----テスト終了-----
.ss
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK (skipped=2)

※2つのテストがスキップされている

▼想定外のNGパターン

$ python3 test_check_number.py 
-----テスト開始-----
---値の確認テスト---
-----テスト終了-----
F-----テスト開始-----
---例外の確認テスト---
-----テスト終了-----
.ss
======================================================================
FAIL: test_check_input_number (__main__.TestCheckInputNumber)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_check_number.py", line 26, in test_check_input_number
    self.assertEqual(self.test_target.check_input_number(4), 10)
AssertionError: 20 != 10

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (failures=1, skipped=2)

一つ目のテストが、実測値:20、期待値:10であるためNG

■参考

タイトルとURLをコピーしました