こんにちは。KOUKIです。
今日は、Pythonのテストツールのまとめをします。
※ここでは簡単な使い方だけ紹介します
<目次>
Python テストツールについて
次の4つのテストツールをご紹介します。
- doctest
- unittest
- pytest
- selenium
seleniumは、厳密にはpythonのテストツールではありませんが、便利なので追加しました。
doctest
最初は、doctestです。
以下、公式サイトからdockerテストの引用です。
doctest モジュールは、対話的 Python セッションのように見えるテキストを探し出し、セッションの内容を実行して、そこに書かれている通りに振舞うかを調べます。 doctest は以下のような用途によく使われています:
モジュールの docstring (ドキュメンテーション文字列) 中にある対話実行例のすべてが書かれている通りに動作するか検証することで、docstring の内容が最新かどうかチェックする。
テストファイルやテストオブジェクト中の対話実行例が期待通りに動作するかを検証することで、回帰テストを実現します。
入出力例を豊富に使ったパッケージのチュートリアルドキュメントが書けます。入出力例と解説文のどちらに注目するかによって、ドキュメントは「読めるテスト」にも「実行できるドキュメント」にもなります。
公式サイトの文章って、小難しいですよね!具体例をお見せします。
calc.pyというファイルを用意して、次のコードを実装してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
calc.py class Calc(object): def add_number_plus_double(self, num1, num2): '''引数同士を足して、2倍する >>> k = Calc() >>> k.add_number_plus_double(10, 10) 30 ''' result = num1 + num2 result *= 2 return result if __name__ == '__main__': import doctest doctest.testmod() |
doctestでは、上記の通り、「コメントの中にテストを書く」のです。
このプログラムを実行すると次の出力結果を得られます。
1 2 3 4 5 6 |
Failed example: k.add_number_plus_double(10, 10) Expected: 30 Got: 40 |
「30」と予想した計算結果が実際は「40」だったため、エラーになりました。
30→40にしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Calc(object): def add_number_plus_double(self, num1, num2): '''引数同士を足して、2倍する >>> k = Calc() >>> k.add_number_plus_double(10, 10) 40 ''' result = num1 + num2 result *= 2 return result if __name__ == '__main__': import doctest doctest.testmod() |
今度は、何も出力されなくなりました。
doctest は、このように簡単に挙動のチェックができます。
UnitTest
次は、unittestについて学びましょう。
公式サイトによるとこのようなテストフレームワークです。
unittest ユニットテストフレームワークは元々 JUnit に触発されたもので、 他の言語の主要なユニットテストフレームワークと同じような感じです。 テストの自動化、テスト用のセットアップやシャットダウンのコードの共有、テストのコレクション化、そして報告フレームワークからのテストの独立性をサポートしています。
pythonは便利な言語で、既にテストフレームワークを内部に実装しています。
unittestは、主に単体テストで用いられます。
doctestで書いた処理をunittestに置き換えてみましょう。
次の構成になるようにファイルを用意してください。
1 2 3 |
python_test_sample L calc.py L calc_test.py |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
calc.py class Calc(object): def add_number_plus_double(self, num1, num2): if type(num1) is not int or type(num2) is not int: raise ValueError # 足し算 result = num1 + num2 # 2倍する result *= 2 return result |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
calc_test.py import unittest import calc class Calc(unittest.TestCase): def test_add_number_plus_double(self): c = calc.Calc() result = c.add_number_plus_double(10, 20) self.assertEqual(result, 40) if __name__ == '__main__': unittest.main() |
doctestとの違いは、テストコードを別ファイルに分けて管理することです。
より詳細なテストが実施できます。
テストを実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
====================================================================== FAIL: test_add_number_plus_double (__main__.Calc) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\Users\n5289\source\repos\python_sample\python_sample\calc_test.py", line 10, in test_add_number_plus_double self.assertEqual(result, 40) AssertionError: 60 != 40 ---------------------------------------------------------------------- Ran 1 test in 0.003s FAILED (failures=1) |
エラーになりましたね。
予想値が「40」でしたが、実際は60です。
テストコードを書き換えてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
calc_test.py import unittest import calc class Calc(unittest.TestCase): def test_add_number_plus_double(self): c = calc.Calc() result = c.add_number_plus_double(10, 20) self.assertEqual(result, 60) if __name__ == '__main__': unittest.main() |
テストを実行します。
1 2 3 4 5 |
. ---------------------------------------------------------------------- Ran 1 test in 0.002s OK |
pytest
次は、pytestについて学びます。
pytestフレームワークは、スモールテストを簡単に作成できまが、アプリケーションやライブラリに大して、より複雑なことが行えるように拡張することができます。
pytestもunittestと似たようなものです。
次のモジュールをインストールしてください。
1 |
$ pip install pytest |
unittestで書いたテストコードを実行できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
calc_test.py import unittest import calc class Calc(unittest.TestCase): def test_add_number_plus_double(self): c = calc.Calc() result = c.add_number_plus_double(10, 20) self.assertEqual(result, 40) if __name__ == '__main__': unittest.main() |
コマンドプロンプト上からpytestコマンドで、テストを実行しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
pytest __________________________________________ Calc.test_add_number_plus_double ___________________________________________ self = <calc_test.Calc testMethod=test_add_number_plus_double> def test_add_number_plus_double(self): c = calc.Calc() result = c.add_number_plus_double(10, 20) > self.assertEqual(result, 40) E AssertionError: 60 != 40 calc_test.py:10: AssertionError ================================================== 1 failed in 0.13s ================================================== |
pytestは、unittestより機能が豊富で、pytest実行時に次のオプションを付与すると様々なテストを実行できます。
オプションの一部を紹介します。
オプション | 説明 |
---|---|
–help | ヘルプを表示 |
–collect-only | 指定したオプションと構成に基づいて実行されるテストを表示 |
-k EXPRESSION | k オプションは、実行するテスト関数を、式を使って検索できるようにしたフィルタ |
-m | MARKERPR |
selenium
最後に[selenium]を紹介して終わりにします。
selenium は、Webサイトなどを自動でテストするツールです。
下記のコマンドを実行して、仮想環境を作成してください。
1 |
virtualenv venv |
仮想環境構築用のvenvフォルダが作成できたら、venv -> Scripts順に移動してください。
Scriptsフォルダに入ったら次のコマンドを実行してください。
1 2 3 4 5 6 |
# 仮想環境に入る activate # プロンプトの線乙がvenvになったことを確認しseleniumをインストール (venv) > pip install selenium (venv) > pip install pytest |
次に、driverを取得します。
このドライバーをScriptsフォルダ内に格納します。
test_ui.pyファイルを作成して、テストコードを書きましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import pytest # chrom の webdriver の情報 from selenium import webdriver # html の タブの情報を取得 from selenium.webdriver.common.by import By # キーボードを叩いた時に web ブラウザに情報を送信する from selenium.webdriver.common.keys import Keys # 次にクリックしたページがどんな状態になっているかチェックする from selenium.webdriver.support import expected_conditions as EC # 待機時間を設定 from selenium.webdriver.support.ui import WebDriverWait class TestPythonOrgTest(object): def setup_method(self): # webdriver を指定(chorme) self.driver = webdriver.Chrome() def teardown_method(self): self.driver.close() # webdriver の立ち上げ def test_python_org(self): self.driver.get('http://www.python.org') |
仮想環境が有効になっている状態で、test_ui.pyが格納されているディレクトリに移動後、以下のコマンドを実行してください。
1 |
(venv) > pytest |
ブラウザが立ち上がるはずです。
まとめ
個人的には、pytest + seleniumの組み合わせが最強ですね。
テストコードが書けると、現場でも重宝されます。
特にプログラミング初学者の方には、マスターしておいてほしい分野ですね^^
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。