🦁

Pythonでのユニットテストの基本と実践(サンプルコードあり)

2024/09/27に公開

はじめに

Pythonでのユニットテストは、コードの品質を保つために非常に重要です。
この記事では、基本的なユニットテストの書き方と、具体的なサンプルコードを紹介します。

ユニットテストとは?

ユニットテストは、プログラムの最小単位である「ユニット」(関数やメソッド)が正しく動作するかを検証するテストです。これにより、バグの早期発見やコードのリファクタリング時の安心感を得ることができます。

やってみよう

1. テスト対象のコードを作成

まず、テスト対象のコードを作成します。ここでは、基本的な数学関数を実装した
math_functions.py を用意します。

math_functions.py
# math_functions.py

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

def subtract(a, b):
    return a - b

def multiply(a, b):
    return a * b

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero!")
    return a / b

2. ユニットテストの作成

次に、この関数群をテストするためのユニットテストを test_math_functions.py というファイルに作成します。

test_math_functions.py
# test_math_functions.py
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))

import unittest
from math_functions import add, subtract, multiply, divide

class TestMathFunctions(unittest.TestCase):
    
    def test_add(self):
        self.assertEqual(add(1, 2), 3)
        self.assertEqual(add(-1, 1), 0)
        self.assertEqual(add(-1, -1), -2)
        self.assertEqual(add(0, 0), 0)
    
    def test_subtract(self):
        self.assertEqual(subtract(2, 1), 1)
        self.assertEqual(subtract(-1, 1), -2)
        self.assertEqual(subtract(-1, -1), 0)
        self.assertEqual(subtract(0, 0), 0)
    
    def test_multiply(self):
        self.assertEqual(multiply(2, 3), 6)
        self.assertEqual(multiply(-1, 1), -1)
        self.assertEqual(multiply(-1, -1), 1)
        self.assertEqual(multiply(0, 100), 0)
    
    def test_divide(self):
        self.assertEqual(divide(6, 3), 2)
        self.assertEqual(divide(-6, -3), 2)
        self.assertEqual(divide(-6, 3), -2)
        with self.assertRaises(ValueError):
            divide(1, 0)
        with self.assertRaises(ValueError):
            divide(0, 0)

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

3. テストの実行

次に、ターミナルで以下のコマンドを実行してテストを実行します。

python3 test_math_functions.py

これで、ユニットテストが実行され、すべてのテストが成功するかどうかが確認できます。

テストがすべて成功した場合、次のような出力が表示されます。

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

OK

4. テストの拡張

  • テストケースの追加:
    • 異常系やエッジケースのテストも追加してみましょう。
    • 例えば、divide 関数においてゼロ以外のさまざまなケースをテストするなど。
  • テストカバレッジの向上:
    • coverage パッケージを使って、テストカバレッジを確認できます。これにより、どの部分のコードがテストされていないかを把握できます。
インストール: pip install coverage
実行: coverage run -m unittest test_math_functions.py
レポート生成: coverage report
  • 自動化:

    • テストをCI/CDパイプラインに組み込むことで、コードが変更されるたびに自動的にテストが実行されるようにします。GitHub ActionsやTravis CIなどのツールを利用できます。
  • モックとパッチ:

    • 外部依存やI/O操作を行う部分をテストする際には、unittest.mock を利用してモックやパッチを使います。
  • ドキュメントとコメント:

    • テストコードにも適切なコメントを付けることで、他の開発者がテストの目的や意図を理解しやすくなります。

5. まとめ

ユニットテストは、コードの品質を保ち、バグを早期に発見するための重要な手段です。ここでは基本的な数学関数のテストを例に取り上げましたが、他のプロジェクトでも同様の手法でテストを追加していくことができます。
実際に動かしてみると問題なくテストてできました。

また以下のポイントに注意して、効果的なユニットテストを作成していきましょう。

  • テストケースの追加: 異常系やエッジケースのテストを追加する。
  • テストカバレッジの向上: coverage パッケージを使ってテストカバレッジを確認する。
  • 自動化: テストをCI/CDパイプラインに組み込む。

Discussion