PYTHON MEBY

Pythonで関数の単体テストを書く(unittest, pytest)

この記事では、Pythonの`unittest`モジュールと`pytest`フレームワークを使った関数の単体テストの書き方について説明します。様々なテストパターンや、テストを効率的に行うためのテクニックを紹介します。

目次

unittestモジュールによる単体テスト

Python標準ライブラリの`unittest`モジュールは、単体テストを作成するためのフレームワークを提供します。`TestCase`クラスを継承し、テストメソッドを作成することで、関数のテストを行うことができます。

import unittest

def add(x, y):
    return x + y

class TestAdd(unittest.TestCase):
    def test_add_positive(self):
        self.assertEqual(add(2, 3), 5)
    def test_add_negative(self):
        self.assertEqual(add(-2, 3), 1)
    def test_add_zero(self):
        self.assertEqual(add(0, 0), 0)

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

上記は`add`関数のテストケースです。`assertEqual`メソッドを使って期待値と実際の値を比較しています。`if __name__ == '__main__':` のブロックは、スクリプトを直接実行した際にテストを実行するためのものです。

テストケースの作成

テストケースは、`test_`で始まるメソッド名で定義します。`unittest`は`test_`で始まるメソッドを自動的にテストケースとして認識します。

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')
    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())
    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        with self.assertRaises(TypeError):
            s.split(2)

複数のテストケースを作成することで、関数の様々な側面をテストできます。`assertRaises`コンテキストマネージャーを使って例外処理もテストできます。

setUp()とtearDown()メソッド

`setUp()`メソッドは各テストケースの前に実行され、テストに必要な環境を準備するために使用します。`tearDown()`メソッドは各テストケースの後で実行され、使用したリソースを解放するために使用します。

import unittest

class TestSetupTeardown(unittest.TestCase):
    def setUp(self):
        print('Setup')
    def tearDown(self):
        print('Teardown')
    def test_case1(self):
        print('Test Case 1')
        self.assertTrue(True)
    def test_case2(self):
        print('Test Case 2')
        self.assertTrue(True)

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

アサーション

テスト結果の検証には、アサーションメソッドを使用します。`assertEqual`, `assertTrue`, `assertFalse`, `assertRaises`など、様々なアサーションメソッドがあります。

self.assertEqual(a, b) # aとbが等しいことを検証
self.assertTrue(x) # xがTrueであることを検証
self.assertFalse(y) # yがFalseであることを検証
with self.assertRaises(ValueError): # ValueError例外が発生することを検証
    some_function()

テストの実行

コマンドラインから`python -m unittest <test_module>.py`を実行することで、テストを実行できます。`test_module.py`はテストケースを含むPythonファイルです。

python -m unittest test_my_module.py

pytestフレームワークによる単体テスト

`pytest`は、`unittest`よりも簡潔で使いやすいテストフレームワークです。`unittest`と同様に、関数のテストを行うことができますが、より少ないコードでテストを作成できます。

import pytest

def add(x, y):
    return x + y

def test_add_positive():
    assert add(2, 3) == 5
def test_add_negative():
    assert add(-2, 3) == 1
def test_add_zero():
    assert add(0, 0) == 0

pytestでは、`assert`文を使って期待値と実際の値を比較します。テスト関数の名前は`test_`で始める必要があります。

fixtureを使ったテスト

fixtureは、テストに必要な環境を準備するための関数です。`@pytest.fixture`デコレータを使ってfixtureを定義します。

import pytest

@pytest.fixture
def data():
    return [1, 2, 3]

def test_data(data):
    assert sum(data) == 6

parametrizeを使ったテスト

`@pytest.mark.parametrize`デコレータを使うことで、複数のテストケースを簡単に作成できます。

import pytest

@pytest.mark.parametrize('x, y, expected',
    [(2, 3, 5), (-2, 3, 1), (0, 0, 0)])
def test_add(x, y, expected):
    assert add(x, y) == expected

テストの実行とレポート

コマンドラインから`pytest`を実行することで、テストを実行し、結果をレポートとして出力します。`-v`オプションを付けることで、より詳細なレポートを得ることができます。

pytest
pytest -v

関連記事