Pythonの学習が少し進むと、自分で書いたコードが本当に正しく動いているのか気になる場面が増えてきます。
最初はprintで確認すれば十分に感じるかもしれません。けれど、コードが増えるほど確認作業は面倒になり、修正のたびに前の機能が壊れていないか不安になります。
そこで役立つのがテストです。
この記事では、Pythonのテストフレームワークであるpytestについて、IT初心者にもわかりやすく解説します。インストール方法、基本的なテストの書き方、よく使う機能、実務での考え方まで、順番に見ていきましょう。
pytestとは¶
pytestは、Pythonでテストを書くための便利なツールです。
Pythonには標準ライブラリとしてunittestも用意されていますが、pytestはよりシンプルな書き方でテストを始められる点が大きな魅力です。公式ドキュメントでも、pytestは小さなテストを書きやすく、複雑な機能テストにも対応できるフレームワークとして説明されています。
テストと聞くと、難しそうに感じる人もいるかもしれません。
しかしpytestの最初の一歩はとてもシンプルです。関数を用意し、期待する結果をassertで確認するだけで、基本的なテストを書けます。
たとえば、足し算をする関数が正しく動くかを確認するなら、次のように書けます。
# test_calc.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
この例では、add(2, 3)の結果が5になることを確認しています。
もし結果が5であればテストは成功し、違う値であれば失敗します。とても素直ですよね。
なぜPython初心者こそpytestを学ぶべきなのか¶
初心者のうちは、まず動くコードを書くことに集中しがちです。
もちろん、それは大切です。ただ、動くように見えるコードと、安心して直せるコードは別物です。
プログラムは一度書いて終わりではありません。あとから機能を追加したり、バグを直したり、別の人が読んだりします。
そのときにテストがあると、変更しても大丈夫かを自動で確認できます。
pytestを学ぶことは、コードを安全に育てる力を身につけることでもあります。
私自身の実感として、初心者の段階でテストに触れている人は、コードの修正に対する怖さが少ないです。反対に、テストを書く習慣がないまま実務に入ると、ちょっとした変更でも毎回手作業で確認することになり、時間も精神力も削られます。
最初から完璧なテストを書く必要はありません。
まずは、小さな関数に対して1つテストを書く。それだけでも、コードとの向き合い方は変わります。
pytestでできることをざっくり理解しよう¶
pytestは単にテストを実行するだけのツールではありません。
小さな確認から、実務で使うような本格的なテストまで対応できます。ここで、よく使う機能を整理しておきましょう。
| 機能 | 内容 | 初心者の理解ポイント |
|---|---|---|
| assert | 結果が期待通りか確認する | まず最初に覚える基本 |
| 自動検出 | test_で始まるファイルや関数を見つける | 実行が簡単になる |
| fixture | テスト前の準備を共通化する | 同じ準備コードを減らせる |
| parametrize | 複数パターンをまとめてテストする | 入力と結果の組み合わせに便利 |
| raises | エラーが起きることを確認する | 異常系のテストに使う |
| marker | テストに目印をつける | 一部のテストだけ実行しやすい |
最初から全部覚えようとしなくて大丈夫です。
まずはassertと自動検出を理解し、次にfixtureやparametrizeへ進む流れがおすすめです。
pytestのインストール方法¶
pytestはPythonの外部ライブラリなので、基本的にはpipでインストールします。
プロジェクトごとに環境を分けたい場合は、先に仮想環境を作っておくと安全です。学習中でも、仮想環境に慣れておくと後でかなり役立ちます。
python -m venv .venv
source .venv/bin/activate
pip install pytest
Windowsの場合、仮想環境の有効化は次のようになります。
.venv\Scripts\activate
pip install pytest
インストールできたか確認するには、次のコマンドを使います。
pytest --version
バージョンが表示されれば準備完了です。
【関連記事】Pythonの仮想環境(venv)って何のためにある?プロジェクトごとに混ぜない管理法
はじめてのpytestを書いてみよう¶
ここからは、実際にpytestでテストを書いてみます。
まず、次のようなファイル構成を考えます。小さな学習用プロジェクトなら、これくらいで十分です。
sample_project/
├── calc.py
└── test_calc.py
calc.pyには、計算用の関数を書きます。
# calc.py
def add(a, b):
return a + b
def divide(a, b):
return a / b
次に、test_calc.pyにテストを書きます。
# test_calc.py
from calc import add, divide
def test_add():
assert add(2, 3) == 5
def test_divide():
assert divide(10, 2) == 5
同じフォルダで次のコマンドを実行します。
pytest
pytestは、現在のディレクトリとその下にあるテストを自動で探して実行します。公式ドキュメントでは、test_.pyや_test.pyのようなファイルが標準的に検出対象になると説明されています。
つまり、ファイル名や関数名にtest_をつけることが大切です。
assertの基本を理解する¶
pytestの中心になるのがassertです。
assertは、条件が正しいかどうかを確認するPythonの構文です。条件がTrueなら何も起きず、Falseならテストが失敗します。
def test_number():
assert 1 + 1 == 2
これは成功します。
一方で、次のテストは失敗します。
def test_number_fail():
assert 1 + 1 == 3
pytestの便利なところは、失敗したときにどこが違ったのかを見やすく表示してくれる点です。
初心者のうちは、失敗表示を見ると焦るかもしれません。でもテストの失敗は悪いことではありません。
失敗は、コードや期待値を見直すためのヒントです。
むしろ、実行前にバグを見つけてくれたと考えると、pytestが味方に見えてきます。
テストの名前はわかりやすくする¶
テストを書くときは、名前のつけ方も大切です。
pytestではtest_で始まる関数がテストとして扱われます。ただし、test_の後ろは自由に決められます。
たとえば、次の2つを比べてみましょう。
def test_1():
assert add(2, 3) == 5
def test_add_returns_sum_when_two_numbers_are_given():
assert add(2, 3) == 5
後者のほうが、何を確認しているのかが読み取りやすいです。
長すぎる名前は読みにくくなりますが、短すぎる名前も後から困ります。実務では、テスト名がそのまま仕様書のような役割を持つこともあります。
私も現場で、過去の仕様を知りたいときにテスト名を読むことがよくあります。
コメントよりテストのほうが信頼できる場面もあります。なぜなら、テストは実行できるからです。
エラーが起きることをテストする¶
テストは、正しく動くことだけを確認するものではありません。
エラーが起きるべき場面で、ちゃんとエラーが起きるかも確認できます。
たとえば、0で割ったらZeroDivisionErrorが起きることをテストしてみます。
import pytest
from calc import divide
def test_divide_by_zero():
with pytest.raises(ZeroDivisionError):
divide(10, 0)
このようなテストを異常系のテストと呼ぶことがあります。
初心者のうちは、正常に動くパターンだけを確認しがちです。でも実務では、想定外の入力やエラー処理のほうが重要になる場面も多いです。
ユーザーが必ず正しい値を入力してくれるとは限りません。
だからこそ、エラーになるべきところをテストしておく価値があります。
複数パターンをparametrizeでまとめる¶
同じ関数に対して、いくつもの入力パターンを試したいことがあります。
たとえば、足し算のテストを複数書くと、次のようになります。
def test_add_1():
assert add(1, 2) == 3
def test_add_2():
assert add(-1, 1) == 0
def test_add_3():
assert add(0, 0) == 0
これでも動きますが、少し冗長です。
pytestでは、pytest.mark.parametrizeを使うことで、複数の入力と期待値をまとめて書けます。
import pytest
from calc import add
@pytest.mark.parametrize(
"a, b, expected",
[
(1, 2, 3),
(-1, 1, 0),
(0, 0, 0),
],
)
def test_add(a, b, expected):
assert add(a, b) == expected
この書き方に慣れると、テストケースを追加しやすくなります。
特に、入力値と期待結果の組み合わせをたくさん確認したいときに便利です。
fixtureでテストの準備を共通化する¶
テストでは、実行前にデータを用意したいことがあります。
毎回同じ準備を書くと、コードが長くなり、修正も面倒になります。そこで使うのがfixtureです。
fixtureは、テストの前に必要な準備を共通化する仕組みです。
import pytest
@pytest.fixture
def sample_user():
return {"name": "Taro", "age": 20}
def test_user_name(sample_user):
assert sample_user["name"] == "Taro"
def test_user_age(sample_user):
assert sample_user["age"] == 20
sample_userというfixtureを定義すると、テスト関数の引数として受け取れます。
最初は少し不思議に見えるかもしれません。関数を呼び出していないのに、引数に書くだけで値が入ってくるからです。
でも慣れると、とても便利です。
同じ準備を何度も書かずに済むので、テスト全体が読みやすくなります。公式ドキュメントでも、fixtureはテストが信頼でき、繰り返し可能な結果を出すための基準を用意するものとして説明されています。
pytestとunittestの違い¶
Pythonでテストを調べると、pytestとunittestの両方が出てきます。
どちらを使えばいいのか迷いますよね。ざっくり違いを整理すると、次のようになります。
| 項目 | pytest | unittest |
|---|---|---|
| 位置づけ | 外部ライブラリ | 標準ライブラリ |
| 書き方 | 関数ベースで始めやすい | クラスベースが基本 |
| 検証方法 | assertをそのまま使える | assertEqualなどのメソッドを使う |
| 拡張性 | プラグインが豊富 | 標準機能中心 |
| 初心者へのおすすめ度 | 始めやすい | 標準を学ぶ目的なら有用 |
unittestにも良さがあります。
標準ライブラリなので追加インストールなしで使えますし、既存のプロジェクトで使われていることもあります。
ただ、これからPythonでテストを書き始めるなら、pytestのほうが入りやすいと感じる人は多いはずです。
私も、新規のPythonプロジェクトではpytestを選ぶことが多いです。理由はシンプルで、書き始めが軽く、あとからfixtureやプラグインで広げやすいからです。
テストを書くタイミング¶
では、テストはいつ書けばいいのでしょうか?
理想を言えば、コードを書く前や同時にテストを書くのが望ましいです。いわゆるテスト駆動開発に近い考え方です。
ただ、初心者がいきなりそこを目指すと大変です。
まずは、動くコードを書いたあとにテストを追加する形で十分です。特に、何度も使う関数や、バグが出ると困る処理からテストを書いてみましょう。
たとえば、料金計算、日付処理、入力チェック、データ変換などはテストの効果が出やすいです。
このあたりは人間が手で確認するとミスしやすい部分でもあります。
初心者がpytestでつまずきやすいポイント¶
pytestは始めやすいツールですが、最初につまずきやすいところもあります。
特に多いのは、テストが実行されないという悩みです。
原因としては、ファイル名や関数名がpytestのルールに合っていないケースがよくあります。test_で始まるファイル名、test_で始まる関数名になっているか確認しましょう。
次に多いのが、importで失敗するケースです。
テストファイルから対象のPythonファイルを読み込めないと、テストの前にエラーになります。最初は同じフォルダに置いて、シンプルな構成で試すのがおすすめです。
また、テストが失敗したときに、コードが悪いのかテストが悪いのかわからなくなることもあります。
この場合は、入力、実際の結果、期待する結果を一つずつ確認しましょう。テストもコードなので、テスト側に間違いがあることも普通にあります。
実務で役立つpytestの考え方¶
実務でpytestを使うときに大切なのは、すべてをテストしようとしすぎないことです。
もちろん品質は大切です。けれど、何でもかんでもテストすると、今度はテストの保守が大変になります。
私が現場で意識しているのは、壊れると困るところから優先してテストすることです。
たとえば、売上計算、権限チェック、外部APIのレスポンス処理、データベースに保存する前の変換処理などです。こうした部分は、バグがあると影響が大きくなりがちです。
一方で、画面の細かい表示文言や、すぐに変わる仕様を細かくテストしすぎると、変更のたびにテストが壊れて疲れてしまいます。
良いテストは、安心を増やし、変更の邪魔をしないテストです。
この感覚は、実際に書きながら少しずつ身についていきます。
pytestを学ぶおすすめの順番¶
pytestは機能が多いので、学ぶ順番を決めると挫折しにくくなります。
最初は、全部を理解しようとせず、よく使う機能から触れていきましょう。
- assertで簡単なテストを書く
- pytestコマンドでテストを実行する
- pytest.raisesでエラーのテストを書く
- parametrizeで複数パターンをまとめる
- fixtureで準備処理を共通化する
この順番なら、初心者でも無理なく進めます。
特にfixtureは便利ですが、最初から使いすぎると何がどこで準備されているのか見失うことがあります。まずは普通のテストを書き、重複が増えてきたらfixtureにするくらいで十分です。
まとめ¶
pytestは、Pythonでテストを書くための強力で使いやすいツールです。
最初は難しく考える必要はありません。test_で始まるファイルを作り、test_で始まる関数を書き、assertで期待する結果を確認する。まずはそこから始めましょう。
テストを書くと、自分のコードに対する安心感が増えます。
修正しても壊れていないか確認できるので、コードを改善する勇気も出てきます。これは、学習中の人にとっても、実務のエンジニアにとっても大きなメリットです。
一つの関数に一つのテストを書く。それだけでも、Python学習はかなり実務に近づきます。
pytestは、初心者が次のステップへ進むためのとても良い入口です。今日書いたコードに、まずは一つだけテストを追加してみてください。
ここまでお読みいただきありがとうございました。