機械学習好きのメモ帳

MMのメモ帳

機械学習、データ分析、アルゴリズムなどを扱っていきます。雑記も含まれます。

Pythonで単体テストを行うためのunittestモジュール

unittest

ユニットテスト単体テスト)では関数に対して、実際の「戻り値」と想定される「期待値」を比較して正しい動作をしているか確認します。

まず始めにunittestの簡単な例を見てみましょう。

import unittest

# テスト対象のplus関数
def plus(a, b):
    return a + b

# テストクラス
class TestPlus(unittest.TestCase):
    # テストする関数ごとにメソッドを作る
    def test_plus(self):
        self.assertEqual(5, plus(2, 3))

上記では足し算をする関数を用意してそれが正しく動作するかを確認するテストを書いています。
テストプログラムを書くときは、

  1. unittestをインポートする。
  2. unittest.TestCaseを継承してクラスを作成する。
  3. テストしたい機能ごとにメソッドを作りテストする。

のような流れになります。
assertEqualは二つの引数の値が等しいかどうか比べます。TestCaseにはこのようなメソッドがいくつか用意されています。
本来はテストはテストだけを行う別のpythonファイルにまとめる方が良いです。

テストを実行する方法はいくつかありますが、ここではとりあえず以下のようにします。

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

これを実行すると以下のような出力が得られます。

> python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

テストに失敗する場合は以下のようになります。

> python test.py
F
======================================================================
FAIL: test_plus (__main__.TestPlus)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 11, in test_plus
    self.assertEqual(6, plus(2, 3))
AssertionError: 6 != 5

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

アサートメソッド

TestCaseクラスにあるアサートメソッドをいくつか紹介していきます。
assertEqual(a, b)は上記の通りなので省略。

assertNotEqual(a, b)

aとbが等しく無いことをテストします。

import unittest

def plus(a, b):
    return a + b

class TestPlus(unittest.TestCase):
    def test_plus(self):
        self.assertNotEqual(6, plus(3, 5))

assertTrue(x), assertFalse(x)

xがTrue(False)であることをテストします。

import unittest

class TestStringMethod(unittest.TestCase):
    def test_is_digit(self):
        self.assertTrue('123'.isdigit())

    def test_is_not_digit(self):
        self.assertFalse('mm'.isdigit())

assertIn(a, b), assertNotIn(a, b)

aがbに含まれていること(そうでないこと)をテストします。

import unittest

class TestList(unittest.TestCase):
    def test_is_in(self):
        self.assertIn('a', ['a', 'b', 'c'])

    def test_is_not_in(self):
        self.assertNotIn('x', ['a', 'b', 'c'])

assertGreaterEqual(a, b), assertLess(a, b)

aがb以上か(未満か)をテストします。

import unittest

def plus(a, b):
    return a + b

class TestGreaterOrLess(unittest.TestCase):
    def test_greaterequal(self):
        self.assertGreaterEqual(5, plus(1, 3))

    def test_less(self):
        self.assertLess(2, plus(2, 4))

assertRaises(exc)

with内で例外をあげるかテストします。
関数を実行して例外excが放出されたら成功、他の例外が放出、または例外がなかったら失敗です。

import unittest

def raise_value_error():
    raise ValueError

class TestRaises(unittest.TestCase):
    def test_raises(self):
        with self.assertRaises(ValueError):
            raise_value_error()

まとめ

改めてテストする流れを示しておきます。

  1. unittestをインポートする。
  2. unittest.TestCaseを継承してクラスを作成する。
  3. テストしたい機能ごとにメソッドを作りテストする。

まだまだ多くのアサートメソッドがありますが、ここでは代表的なものをいくつか紹介しました。
テストコードを書くことで、ゴールが明確になったりプログラムが洗練されるなどのメリットがあります。
積極的にテストコードを書いて身につけていきたいです。

公式ドキュメント:
unittest --- ユニットテストフレームワーク — Python 3.7.4 ドキュメント