ざきの学習帳(旧 zackey推し )

日々の学びを書きます

【Python】unittest.TestCase.subTest ブロックで、データをループするテストケースのエラーをすべて出力する

Effective PythonsubTestの存在を知ったため、
メモとして書き残しておこうと思います。

Effective Python 第2版 ―Pythonプログラムを改良する90項目

Effective Python 第2版 ―Pythonプログラムを改良する90項目

  • 作者:Brett Slatkin
  • 発売日: 2020/07/16
  • メディア: 単行本(ソフトカバー)

unittest.TestCase.subTest とは

Pythonに組み込まれているunittestにおいて、
Python3.4からsubTestという関数が実装されました。

subTest内で実行した検証(assert_hogehoge)は、失敗しても終了しないため、
1つのテストケース内で複数件のデータをまとめて検証するのに有効...と思いました。

サンプルコード

python-remote-container/src/effective/09/76_test.pyのコードから抜粋します。

class Logic:
    @classmethod
    def to_str(cls, data):
        if isinstance(data, str):
            return data
        elif isinstance(data, bytes):
            return data.decode("utf-8")
        else:
            raise TypeError(f"Must supply str or bytes, found: {data!r}")


from unittest import TestCase, main


class DataDrivenTestCase(TestCase):
    def test_good(self):
        good_cases = [
            (b"my bytes", "my bytes"),
            ("no error", b"no error"),  # 失敗ケース
            ("aaa", "bbb"),  # 失敗ケース
            ("other str", "other str"),
        ]
        for value, expected in good_cases:
            with self.subTest(value):
                self.assertEqual(expected, Logic.to_str(value))


if __name__ == "__main__":
    main()
# 実行結果
pwd
/code

python src/effective/09/76_test.py DataDrivenTestCase
======================================================================
FAIL: test_good (__main__.DataDrivenTestCase) [no error]
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/code/src/effective/09/76_test.py", line 55, in test_good
    self.assertEqual(expected, Logic.to_str(value))
AssertionError: b'no error' != 'no error'

======================================================================
FAIL: test_good (__main__.DataDrivenTestCase) [aaa]
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/code/src/effective/09/76_test.py", line 55, in test_good
    self.assertEqual(expected, Logic.to_str(value))
AssertionError: 'bbb' != 'aaa'
- bbb
+ aaa


----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (failures=2)

通常では、
AssertionError: b'no error' != 'no error'でテストが中断され、
すべてのテストケースを確認することができません。

subTestを使うことで、
("no error", b"no error")以降(("aaa", "bbb"))のテストケースも実行可能です。

おわり

以上です。

Python3.4から使用可能なので、注意してください。