Pythonでの単体テストのやり方を、基礎から解説をします。具体的には、unittestの使い方を解説します。
unittestはPython標準のテストツールです。
この記事を読めば、Pythonで単体テストが書けるようになります。
この記事を書いた人
- エンジニア歴10数年
- SIerでDX推進を仕事に
- Python、AWSを使ったアーキテクチャ設計・アプリ開発が得意
- 30代、2児の父でサウナ好き
- [icon-class=”icon-twitter”]Twitter
単体テストを書くメリット・デメリットは、以下の通りです。
メリット | デメリット |
---|---|
一度作れば、自動テストができて、作業量が激減する リファクタリング(一度書いたコードの修正)がしやすくなり、保守性が上がる デグレーション(修正時に、意図しない不具合が発生)を防げるので、かっこ悪い謝罪が少なくなる | 学習コストが高い テストコードを書く工数が余計にかかる テストしやすいように、コードを修正する場合がある |
デメリットはありますが、単体テストのコードを書けると、デメリットを上回る幸せな結果を得られます。
基礎から解説しますので、この機会に単体テストのコードを書けるようになりましょう!
unittestと互換性があり、もう少し書きやすいpytestの使い方を解説した記事もあります。
Pythonを勉強する時、何から勉強するか分からず、挫折します。初心者でも、中級者でも、レベルに合わせた勉強方法を分かりやすくまとめています。
Pythonで単体テストを実装する4ステップ
Pythonで単体テストを実装するためには、以下の4ステップが必要です。
- unittestをインポートする。
- unittest.TestCaseを継承して、クラスを作成する。
- テスト用の関数を作成する。
- assertEqual等のAssertメソッドを利用して、テスト内容を記述する。
以下からは4ステップの詳細について、FizzBuzzのプログラムを例に解説をしていきます。
テスト対象のコードは以下となります。
def fizzbuzz(num):
if num % 15 == 0:
return 'FizzBuzz'
elif num % 3 == 0:
return 'Fizz'
elif num % 5 == 0:
return 'Buzz'
else:
return str(num)
ステップ1:unittestをインポート
ステップ1では、単体テストのライブラリである「unittest」をインポートします。
以下のようにunittestをインポートするだけで、単体テストのコードが書けるようになります。
import unittest
unittestはPythonに標準で入っているため、pipでインストールする必要がありません。
簡単ですね!
ステップ2:unittest.TestCaseを継承して、クラスを作成
ステップ2では、インポートしたunittestからTestCaseを継承して、クラスを作成します。慣例として、クラス名の頭にはTestと付けることが多いです。
例としては、以下のような感じです。
import unittest
class TestFizzBuzz(unittest.TestCase):
# 以下にテスト用の関数を書く
ステップ3:テスト用の関数を作成
単体テストをするにはテスト用に関数を作成します。関数名の頭には、「test_」を付けます。
例としては以下のようになります。
import unittest
class TestFizzBuzz(unittest.TestCase):
def test_fizzbuzz_fizz(self):
# ここにテスト内容を書く
ステップ4:関数にテスト内容を記述
ステップ4では、関数の中にテスト内容のコードを書いていきます。
具体的には、assertEqual等のAssertメソッドを利用して、期待値と実際の値を比較します。
サンプルコードは以下となります。
import unittest
class TestFizzBuzz(unittest.TestCase):
def test_fizzbuzz_fizz(self):
"""3の倍数のテスト."""
self.assertEqual(fizzbuzz(9), 'Fizz')
def test_fizzbuzz_buzz(self):
"""5の倍数のテスト."""
self.assertEqual(fizzbuzz(55), 'Buzz')
def test_fizzbuzz_fizzbuzz(self):
"""15の倍数のテスト."""
self.assertEqual(fizzbuzz(45), 'FizzBuzz')
def test_fizzbuzz_not_fizzbuzz(self):
"""3と5の倍数以外のテスト."""
self.assertEqual(fizzbuzz(11), '11')
if __name__ == "__main__":
unittest.main()
以下のようにassertEqualメソッドを使用して、テストをしています。
def test_fizzbuzz_fizz(self):
"""3の倍数のテスト."""
self.assertEqual(fizzbuzz(9), 'Fizz')
第1引数は実際の値、第2引数には期待値を渡します。
Assertメソッドの一覧については、以下を参考にしてください。
メソッド | 確認事項 |
---|---|
assertEqual(a, b) | a == b |
assertNotEqual(a, b) | a != b |
assertTrue(x) | bool(x) is True |
assertFalse(x) | bool(x) is False |
assertIs(a, b) | a is b |
assertIsNot(a, b) | a is not b |
assertIsNone(x) | x is None |
assertIsNotNone(x) | x is not None |
assertIn(a, b) | a in b |
assertNotIn(a, b) | a not in b |
assertIsInstance(a, b) | isinstance(a, b) |
assertNotIsInstance(a, b) | not isinstance(a, b) |
単体テストコードを実行
ここまでで、単体テストのコードが書けました。
今回作成したコードの全体像はこちらです。
import unittest
def fizzbuzz(num):
if num % 15 == 0:
return 'FizzBuzz'
elif num % 3 == 0:
return 'Fizz'
elif num % 5 == 0:
return 'Buzz'
else:
return str(num)
class TestFizzBuzz(unittest.TestCase):
def test_fizzbuzz_fizz(self):
"""3の倍数のテスト."""
self.assertEqual(fizzbuzz(9), 'Fizz')
def test_fizzbuzz_buzz(self):
"""5の倍数のテスト."""
self.assertEqual(fizzbuzz(55), 'Buzz')
def test_fizzbuzz_fizzbuzz(self):
"""15の倍数のテスト."""
self.assertEqual(fizzbuzz(45), 'FizzBuzz')
def test_fizzbuzz_not_fizzbuzz(self):
"""3と5の倍数以外のテスト."""
self.assertEqual(fizzbuzz(11), '11')
if __name__ == "__main__":
unittest.main()
コードが分かりやすいように、テスト対象の処理とテストコードを同じファイルに記述しています。
さて、ここまで来たら単体テストコードを実行してみましょう。
以下のようにコマンドを打つと、テストが実行されます。
$ python test_fizzbuzz.py
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
4つのテストが全てパスしていることが分かります。
次は、わざとテストコードを間違えてみます。
def test_fizzbuzz_fizz(self):
"""3の倍数のテスト."""
self.assertEqual(fizzbuzz(2), 'Fizz')
すると、以下のようになりました。
$ python test_fizzbuzz.py
.F..
======================================================================
FAIL: test_fizzbuzz_fizz (__main__.TestFizzBuzz)
3の倍数のテスト.
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fizzbuzz.py", line 19, in test_fizzbuzz_fizz
self.assertEqual(fizzbuzz(2), 'Fizz')
AssertionError: '2' != 'Fizz'
- 2
+ Fizz
----------------------------------------------------------------------
Ran 4 tests in 0.001s
期待値と実績値が違うため、エラーとなっていることが分かります。
まとめ – Pythonで単体テストを書く
ここまで、Pythonで単体テストを書く方法を4ステップに分けて記載していきました。
4ステップとは以下でした。
- unittestをインポートする。
- unittest.TestCaseを継承して、クラスを作成する。
- テスト用の関数を作成する。
- assertEqual等のAssertメソッドを利用して、テスト内容を記述する。
単体テストコードが書けるようになれば、コーティングをする効率も品質を上がり、エンジニアとして他の人よりも一歩先にレベルアップすることができます。
ぜひとも、単体テストのコーディング方法をしっかりとマスターして下さい!
またPython標準のunittestの他に、テストツールにはpytestもあります。
pytestの方が直感的に使えますので、そちらを学びたい場合、以下がおすすめです。
pytestの使い方を解説した記事
書籍なら、以下がおすすめ
書籍で唯一、Pythonの単体テストが勉強できる評判の技術書。第2版が出て、更にパワーアップしました。
コメント
コメント一覧 (2件)
[…] 【Python入門】単体テストのやり方【基礎編】 […]
[…] 【Python入門】単体テストのやり方【基礎編】 […]