前回は、モジュールに関数定義し、Pythonスクリプトからインポートすることで関数を再利用できるようにしました。今回は、テストとはそもそも何をすればいいのか考察した後、テストに用いるassert文を紹介します。

そもそも何をテストするのか

本連載では、現段階においてテスト用のプログラムは何も書いていないわけですが、今までは作成したプログラムが正しく動いているかどうかをどうやって判断していたでしょうか? そう、Pythonスクリプトを実行して、期待した値が表示されるかどうかを目視で確認することで判断していましたね。

例えば、前回実装した「main.py」が正しく動いているかどうかを確認するには、次のようにPythonスクリプトを実行し、その出力が期待した値と違いがないかどうかを確認していました。

$ python main.py
True
True

テストでは、今まで目視により確認していた「出力が期待した値と一致するかどうか」をプログラムで検証することになります。それにより、いつ誰が行っても同じ品質でプログラムの動作を検証できるようになるわけです。

さて、それではテストの対象となる「出力」とは一体何でしょうか? 目視で確認していた「出力」はPythonスクリプトの実行結果でしたが、より厳密に言えば確認していたのは「関数の戻り値」です。例えば、次のコードでは、match.check_match関数の戻り値を変数matched_fujiに束縛し、その値を表示しています。

patterns = ["富士山.*高さ", "東京.*区.*いくつ"]
text_fuji = "ねぇ、富士山の高さは?"
matched_fuji = match.check_match(patterns, text_fuji)
print(matched_fuji)

これはつまり、match.check_match関数の戻り値をチェックしていることにほかなりません。

ということは、今回のテストではmatch.check_match関数に引数を渡して実行し、その戻り値が期待する値かどうかをチェックすればいいわけですね。関数のように小さな単位でのテストは、プログラミングでは一般的に行われるもので「ユニットテスト」と呼ばれます。頭の片隅に留めておいてください。

assert文での判定

今回のテストでは、関数実行の戻り値が期待する値と等しいかどうかをチェックすればよいことがわかりました。Pythonでは、こうした確認に便利なassert文を提供しています。

assert文は、「assert」に続けてブール値を記述し、ブール値が「False」の場合のみエラーを表示してプログラムを終了します。なお、Pythonではプログラム実行中に発生するエラーを「例外」と呼びます。

このassert文がテストでどのように役立つのか見るために、次のような「assertion.py」というPythonスクリプトを作成してみましょう。

# assertion.py - assert 文の使い方
print("Check 1 == 1")
assert 1 == 1

print("Check 1 == 2")
assert 1 == 2

print("Check 1 == 3")
assert 1 == 3

このプログラムでは、2つの値「値1」と「値2」が一致しているかどうかを「==」演算子を使ってassert文で判定します。 assert文による判定の前には、判定を始めることを表すために「Check 値1 == 値2」のように比較する値を表示しています。

1つ目の判定「assert 1 == 1」では、「1」と「1」が同じ値であるかどうかを確認しています。当然、同じ値ですので「1 == 1」は「True」となり、assert文で例外は発生しません。一方で、2つ目の判定「assert 1 == 2」では「1 == 2」の判定結果は「False」となり、assert文で例外が発生します。

例外が発生した時点でプログラムは終了します。したがって、本来であれば3つ目の判定「assert 1 == 3」も例外が発生するのですが、2つ目の判定でプログラムが終了するため、3つ目のassert文は実行されないことになります。

それでは実際に実行して動作を確かめてみましょう。

$ python assertion.py
Check 1 == 1
Check 1 == 2
Traceback (most recent call last):
  File "assertion.py", line 6, in 
    assert 1 == 2
AssertionError

初めの2の判定が行われたことが「Check 1 == 1」「Check 1 == 2」が表示されていることからわかります。また、「Check 1 == 3」が表示されていないことから、プログラムは2つ目の判定の段階で終了し、3つ目のassert文は実行されていないこともわかります。

さて、「Traceback (most recent call last):」以降の出力は初めて見るものです。これは、Pythonが例外を発生して終了した時に表示する出力で「トレースバック」と呼ばれます。このトレースバックを読み解くことで、例外が発生したソースコードの箇所を特定することができるのです。

  File "assertion.py", line 6, in <module>
    assert 1 == 2

この記述では、「assertion.py」というファイルの6行目の「assert 1 == 2」で例外が発生したことを示しています。実行する前に予想していた例外発生箇所と一致するので、期待通りの動作をしていると言えるわけです。

今回は、モジュールに定義した関数が期待する動作をするか確かめるために何をテストすればいいのかについて確認した後、テストに用いるassert文を紹介しました。次回はいよいよ、このassert文を使ってテストを書いてみましょう。

著者紹介


株式会社NTTドコモ
R&Dイノベーション本部 サービスイノベーション部
阿部憲幸

2015年京都大学大学院理学研究科数学・数理解析専攻修了。 同年、NECに入社。 2016年から国立研究開発法人情報通信研究機構出向。 2018年より現職。 自然言語処理、特に対話システムの研究開発に従事。 毎日話したくなるAIを夢見て日夜コーディングに励む。
GitHub:https://github.com/noriyukipy