「テストコードが書けたら良いな」と思いながらも、学習コストが高いため、習得を諦めた人も多いと思います。
メリット | デメリット |
---|---|
一度作れば、自動テストができて、作業量が激減する リファクタリング(一度書いたコードの修正)がしやすくなり、保守性が上がる デグレーション(修正時に、意図しない不具合が発生)を防げるので、かっこ悪い謝罪が少なくなる | 学習コストが高い テストコードを書く工数が余計にかかる テストしやすいように、コードを修正する場合がある |
この記事ではpytestについて、現場で使えるように徹底的に解説します。
具体的には、インストールから始めて、assert文の書き方、fixtureを使った前処理・後処理の実装方法、パラメーター化テストなど、初心者レベルから、中級者レベルまでをカバーした内容となります。
pytestをマスターすれば、品質の高いソフトウェアを開発できて、現場で重宝されると思います。
ちなみに、私の環境のバージョン情報は以下の通りです。
項目 | バージョン |
---|---|
Python | 3.10.6 |
pytest | 7.1.3 |
それでは、最後までよろしくお願いします。
pytestのインストール方法
pytestはPythonの標準ライブラリではないため、pipを利用して、インストールが必要です。
Windowsなら、コマンドプロンプト、Macなら、ターミナルを開いて、以下のコマンドを入力します。
$ pip install pytest
これで、pytestのインストールが完了しました。
実際の現場では、環境差異をなくすため、requirements.txtを使って、モジュールをインストールすることが多いです。
requirements.txtでインストールする方法は以下の記事で詳しく解説しています。
pytestの書き方:命名規則
pytestには、テストコードと認識させるため、命名規則があります。
対象 | ルール |
---|---|
テストファイル名 | test_ hoge.py or hoge_test.py |
テストメソッド名 | test_hoge |
テストクラス名 | TestHoge |
このルールに従うと、test_ hoge.pyの内容は以下となります。
# テストクラス名
class TestHoge():
# テストメソッド名
def test_hoge(self):
assert "test" == "test"
テストコードを動かすと、テストに成功します。
$ pytest
================================================= test session starts ==================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: (省略)
collected 1 item
test_ hoge.py . [100%]
================================================== 1 passed in 0.01s ===================================================
ちなみに、ルールを破って実装すると、
# テストクラス名
class testHoge(): # <= TestHoge()をtestHoge()に変更した
# テストメソッド名
def test_hoge(self):
assert "test" == "test"
テストコードが見つからないと、以下のように警告されます。
$ pytest
================================================= test session starts ==================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: (省略)
collected 0 items
================================================ no tests ran in 0.01s =================================================
assert文の書き方
Pythonでテストをする時は、assert文を利用して、値の正当性を検証します。
assert文を基本として、テストコードを組み立てます。
pytestで使えるasset文の一覧は以下の表の通り。
pytest | unittest | 意味 |
---|---|---|
assert hoge | assertTrue(hoge) | hogeがTrueか検証 |
asser not hoge | assertFalse(hoge) | hogeがFalseか検証 |
assert hoge == fuga | assertEqual(hoge, fuga) | hogeとhugaが同じか検証 |
assert hoge != fuga | assertNotEqual(hoge, fuga) | hogeとhugaが異なるか検証 |
assert hoge is None | assertIsNone(hoge, fuga) | hogeがNoneか検証 |
assert hoge is not None | assertIsNotNone(hoge, fuga) | hogeがNoneではないか検証 |
assert hoge <= fuga | assertLessEqual(hoge, fuga) | hoge <= fugaか検証 |
assert hoge < fuga | assertLess(hoge, fuga) | hoge < fugaか検証 |
assert hoge >= fuga | assertGreaterEqual(hoge, fuga) | hoge >= fugaか検証 |
assert hoge > fuga | assertGreater(hoge, fuga) | hoge > fugaか検証 |
Pythonの標準ライブラリであるunittestで比べて、pytestの方が直感的に書けると感じると思います。
unittestだとメソッド名を忘れてググったりしますが、pytestはやりたいことをそのまま書けるなので、忘れにくいですね。
実装例は以下です。
class TestAssert():
def test_asserts(self):
# hogeがTrueか検証
hoge = True
assert hoge
# hogeがFalseか検証
hoge = False
assert not hoge
# hogeとhugaが同じか検証
assert "hoge" == "hoge"
# hogeとhugaが異なるか検証
assert "hoge" != "fuga"
# hogeがNoneか検証
hoge = None
assert hoge is None
# hogeがNoneではないか検証
hoge = "hoge"
assert hoge is not None
# hoge <= fugaか検証
hoge = 1
fuga = 2
assert hoge <= fuga
# hoge < fugaか検証
hoge = 1
fuga = 2
assert hoge < fuga
# hoge >= fugaか検証
hoge = 2
fuga = 1
assert hoge >= fuga
# hoge > fugaか検証
hoge = 2
fuga = 1
assert hoge > fuga
上記の実装例では、全てのテストケースがpassします。
$ pytest test_assert.py
================================================= test session starts ==================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: (省略)
collected 1 item
test_assert.py . [100%]
================================================== 1 passed in 0.02s ===================================================
pytestで例外を発生させる方法
pytestでは例外の発生についても、検証が可能です。
例えば、以下のような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)
この関数はint型で入力されることを期待していますが、文字列型を渡して、例外を発生させるコードを書いてみます。
import pytest
from src.fizzbuzz import fizzbuzz
@pytest.mark.parametrize(
"num, expected",
[
("15", 'not all arguments converted during string formatting'),
],
)
def test_fizzbuzz_fail(num, expected):
"""
文字列型を渡して、例外を発生
"""
with pytest.raises(TypeError) as exc_info:
fizzbuzz(num)
assert expected in str(exc_info.value)
with pytest.raises(TypeError)はTypeErrorが発生する予定であることを意味します。
もしも、TypeErrorが発生しない場合は、テストケースが失敗します。
例外が出力するエラーメッセージの検証をする場合は、with句に対して、asで別名(今回はexc_info)をつけて、exc_info.valueでメッセージを取得できます。
fixture(フィクスチャ)の使い方
fixture(フィクスチャ)を使えば、テストの前処理、後処理を書けます。
pytest以外のxUnitに詳しいなら、fixtureはsetup()、teardown()に相当すると考えると理解しやすいです。
fixtureを使うと、テスト関数から前処理・後処理を分離できて、シンプルで保守性の高いテストコードが書けます。
fixtureの前処理・後処理でよくやる処理例は以下の通り
項目 | よくやる処理例 |
---|---|
前処理 | DBのセットアップ モック化 パラメータ化 |
後処理 | DBのクローズ処理 tempファイルの削除処理 |
fixtureの使い方を知りたいなら、以下の記事にまとめています。簡単に前処理・後処理が書けるようになります。
パラメーター化
テストを書いていると、同じ処理を異なるデータで検証したい時があります。何も考えないと、似たコードが量産されますが、パラメータ化をすると解決できます。
パラメータ化すれば、短くシンプルなコードで、一つのテスト関数を複数のテストデータで検証できます。
pytestでのパラメータ化には、3つの方法があります。
- テスト関数をパラメータ化:最もスタンダード
- fixtureをパラメータ化:前処理、後処理を書きたい時に利用
- フック関数(pytest_generate_tests)で、パラメータ化:複雑なデータセットを書きたい時に利用
pytestでパラメータテストをする方法は、以下の記事で詳しく解説しています。様々なデータセットで検証できます。
カバレッジの出力方法
テストコードを書いていると、どれくらいテストコードを書くべきか迷うことがあります。その時に有効なのが、カバレッジです。
カバレッジとは、開発したプログラムに対するテストのカバー率のことを言います。カバレッジが高いとテストの網羅率が高いと判断ができます。
pytestなら、カバレッジも簡単に出力することができます。
カバレッジを見れば、どんなテストをどれくらい書いたら良いのかすぐに分かるので、品質の向上につながります。
こんな感じで、カバレッジレポートが見れます
カバレッジを見ない現場はないと言ってもいいかも知れません。
HTML形式で出力可能なので、現場でチームメンバーと共有したい時も便利です。
具体的なpytestでカバレッジを出力する方法については、以下の記事で詳しく解説しています。
コマンドオプションの使い方
pytestを実行する時に、引数に様々なオプションを指定することができます。
pytestでよく使うオプションは以下の通りです。
- –collect-only:実行される予定のテストケースを表示
- -x:テストが失敗した時点で終了する
- -s:print文を出力させる
- –lf:失敗しているテストだけを実行する
- -q:出力する情報を少なくする
- -k:指定した文字列で検索して、テスト実行する
pytestでオプションを使った場合の実行結果については、以下の記事で詳しくまとめています。
pytestのおすすめ勉強法
もっと深くpytestを勉強したいなら、以下がおすすめです。
- 公式ページを読む:情報が最新。でも、初心者には難易度が高い
- Pythonテスト駆動開発 第2版を読む:初心者〜上級者まで学びがある
公式ページ
pytestの公式ページは以下です。
pytestの最新情報はこの公式ページで確認しましょう。
ただし、残念ながら全て英語となっていますので、初心者には難しいかもです。
Pythonテスト駆動開発 第2版
初心者がpytestを学ぶなら、「Pythonテスト駆動開発 第2版」がおすすめです。
- 日本語でpytestの全てについて、解説されている唯一の書籍
- 段々とステップアップして、深くなるので、初心者でも、中級者でも、上級者でも、学びがある
- サンプルコードには、サンプルアプリが含まれているため、実践的に学べる工夫あり
- 章末にまとめがあり、復習の役に立つ
- 第7章に「どのようなテストを書くのか」についての解説があり、テストに対する考え方が深まる
- 後半になると、かなり高度な内容になるため、初心者には難しい
- タイトルに「テスト駆動開発」と書かれているが、該当部分の記述が少なく、テスト駆動開発を知りたい人は期待外れになるかも
pytestについて、必要な全ての知識を解説している唯一の日本語で書かれた技術書となります。
公式ページを読んで諦めた人でも、この書籍であれば、pytestに入門できると思います。
2022年に第2版が出版されて、内容がかなりパワーアップしました。
よくある質問
よくある質問をまとめています。
Pythonに標準的に入っているunittestを使いたい場合、以下の記事が参考になります。
まとめ:pytestで品質の高いPythonコードを書く
ここまでpytestの使い方をサンプルを交えながら、初心者でも入門できるように解説してきました。
ここで紹介した内容は以下の通りです。
- pytestのインストール方法
- pytestの書き方:命名規則
- assert文の書き方
- pytestで例外を発生させる方法
- fixture(フィクスチャ)の使い方:前処理・後処理が書ける
- パラメーター化:複数のデータセットでの検証が簡単に書ける
- カバレッジの出力方法:品質の評価で使える
- コマンドオプションの使い方:効率UP
この内容を使えたら、あなたが書くコードの品質は必ず上がります。品質を上げたいなら、pytestでテストコードを書くことは必須です。
ぜひとも、この記事の内容をしっかりと理解して、品質の高いコードが書けるようになりましょう。
もっとpytstの使い方を学びたい場合は、以下の書籍がおすすめです。
日本語で唯一、pytestだけに焦点を当てて、詳細に書かれた書籍です。
Pythonを勉強する時、何から勉強するか分からず、挫折します。初心者でも、中級者でも、レベルに合わせた勉強方法を分かりやすくまとめています。
コメント