Pytest-quick-guide

提供:Dev Guides
移動先:案内検索

Pytest-はじめに

Pytestはpythonベースのテストフレームワークであり、テストコードの記述と実行に使用されます。 RESTサービスの現在では、pytestは主にAPIテストに使用されていますが、pytestを使用して単純なテストから複雑なテストまで記述できます。つまり、API、データベース、UIなどをテストするコードを記述できます。

Pytestの利点

Pytestの利点は次のとおりです-

  • Pytestは複数のテストを並行して実行できるため、テストスイートの実行時間が短縮されます。
  • Pytestには、明示的に言及されていない場合、テストファイルとテスト機能を自動的に検出する独自の方法があります。
  • Pytestでは、実行中にテストのサブセットをスキップできます。
  • Pytestでは、テストスイート全体のサブセットを実行できます。
  • Pytestは無料のオープンソースです。
  • 単純な構文のため、pytestは非常に簡単に開始できます。

このチュートリアルでは、pytestの基本をサンプルプログラムで説明します。

Pytest-環境設定

この章では、pytestのインストール方法を学びます。

インストールを開始するには、次のコマンドを実行します-

pip install pytest == 2.9.1

pytestの任意のバージョンをインストールできます。 ここで、2.9.1はインストールするバージョンです。

pytestの最新バージョンをインストールするには、次のコマンドを実行します-

pip install pytest

次のコマンドを使用してインストールを確認し、pytestのヘルプセクションを表示します。

pytest -h

テストファイルとテスト関数の特定

ファイル名を指定せずにpytestを実行すると、現在のディレクトリとサブディレクトリで test ' 。py または ' test.py 形式のすべてのファイルが実行されます。 Pytestは、これらのファイルをテストファイルとして自動的に識別します。 明示的に言及することで、pytestに他のファイル名を実行させることができます。

Pytestでは、 test で始まるテスト関数名が必要です。 test 形式ではない関数名は、pytestではテスト関数とは見なされません。 *test で始まらない関数をテスト関数としてpytestに明示的に*許可*することはできません。

後続の章でテストの実行について理解します。

Pytest-基本テストから始める

それでは、最初のpytestプログラムから始めましょう。 最初にディレクトリを作成し、そのディレクトリにテストファイルを作成します。

以下に示す手順に従ってください-

  • automation という名前の新しいディレクトリを作成し、コマンドラインのディレクトリに移動します。
  • test_square.py という名前のファイルを作成し、そのファイルに以下のコードを追加します。
import math

def test_sqrt():
   num = 25
   assert math.sqrt(num) == 5

def testsquare():
   num = 7
   assert 7*7 == 40

def tesequality():
   assert 10 == 11

次のコマンドを使用してテストを実行します-

pytest

上記のコマンドは、次の出力を生成します-

test_square.py .F
============================================== FAILURES
==============================================
______________________________________________ testsquare
_____________________________________________
   def testsquare():
   num=7
>  assert 7*7 == 40
E  assert (7 *7) == 40
test_square.py:9: AssertionError
================================= 1 failed, 1 passed in 0.06 seconds
=================================

結果の最初の行を参照してください。 ファイル名と結果が表示されます。 Fはテストの失敗を表し、dot(。)はテストの成功を表します。

その下に、失敗したテストの詳細が表示されます。 テストが失敗したステートメントが表示されます。 この例では、7* 7が49と等しいかどうか比較されますが、これは間違っています。 最終的に、テスト実行の概要が表示され、1つが失敗し、1つが合格しました。

関数tescompareは、名前が test *の形式ではないため、pytestはテストと見なさないため実行されません。

さて、以下のコマンドを実行し、結果を再度表示します-

pytest -v

-vは冗長性を高めます。

test_square.py::test_sqrt PASSED
test_square.py::testsquare FAILED
============================================== FAILURES
==============================================
_____________________________________________ testsquare
_____________________________________________
   def testsquare():
   num = 7
>  assert 7*7 == 40
E  assert (7 * 7) == 40
test_square.py:9: AssertionError
================================= 1 failed, 1 passed in 0.04 seconds
=================================

これで、結果は失敗したテストと合格したテストについてよりわかりやすくなりました。

注意-pytestコマンドは、現在のディレクトリとサブディレクトリにある test ' または ' test 形式のすべてのファイルを実行します。

Pytest-ファイル実行

この章では、単一のテストファイルと複数のテストファイルを実行する方法を学習します。 テストファイル test_square.py が既に作成されています。 次のコードで新しいテストファイル test_compare.py を作成します-

def test_greater():
   num = 100
   assert num > 100

def test_greater_equal():
   num = 100
   assert num >= 100

def test_less():
   num = 100
   assert num < 200

今、すべてのファイル(ここでは2つのファイル)からすべてのテストを実行するには、次のコマンドを実行する必要があります-

pytest -v

上記のコマンドは、 test_square.pytest_compare.py の両方からテストを実行します。 出力は次のように生成されます-

test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
test_compare.py::test_less PASSED
test_square.py::test_sqrt PASSED
test_square.py::testsquare FAILED
================================================ FAILURES
================================================
______________________________________________ test_greater
______________________________________________
   def test_greater():
   num = 100
>  assert num > 100
E  assert 100 > 100

test_compare.py:3: AssertionError
_______________________________________________ testsquare
_______________________________________________
   def testsquare():
   num = 7
>  assert 7*7 == 40
E  assert (7 * 7) == 40

test_square.py:9: AssertionError
=================================== 2 failed, 3 passed in 0.07 seconds
===================================

特定のファイルからテストを実行するには、次の構文を使用します-

pytest <filename> -v

今、次のコマンドを実行します-

pytest test_compare.py -v

上記のコマンドは、ファイル* test_compare.py。*からのみテストを実行します。結果は-

test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
test_compare.py::test_less PASSED
============================================== FAILURES
==============================================
____________________________________________ test_greater
____________________________________________
   def test_greater():
   num = 100
>  assert num > 100
E  assert 100 > 100
test_compare.py:3: AssertionError
================================= 1 failed, 2 passed in 0.04 seconds
=================================

テストスイートのサブセットを実行する

実際のシナリオでは、複数のテストファイルがあり、各ファイルには多数のテストがあります。 テストでは、さまざまなモジュールと機能をカバーします。 特定のテストセットのみを実行するとします。どうすればいいの?

Pytestは、テストスイートのサブセットを実行する2つの方法を提供します。

  • テスト名の部分文字列一致に基づいて実行するテストを選択します。
  • 適用されたマーカーに基づいて実行するテストグループを選択します。

これらの2つについては、後続の章で例を挙げて説明します。

テスト名の部分文字列一致

名前に文字列を含むテストを実行するには、次の構文を使用できます-

pytest -k <substring> -v

-k <substring>は、テスト名で検索するサブストリングを表します。

今、次のコマンドを実行します-

pytest -k great -v

これにより、名前に「」という単語が含まれるすべてのテスト名が実行されます。 この場合、それらは test_greater()および test_greater_equal()*です。 以下の結果を参照してください。

test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
============================================== FAILURES
==============================================
____________________________________________ test_greater
____________________________________________
def test_greater():
num = 100
>  assert num > 100
E  assert 100 > 100
test_compare.py:3: AssertionError
========================== 1 failed, 1 passed, 3 deselected in 0.07 seconds
==========================

この結果では、3つのテストが選択解除されていることがわかります。 これは、それらのテスト名に great という単語が含まれていないためです。

-テスト関数の名前は、「test」で始まる必要があります。

Pytest-テストのグループ化

この章では、マーカーを使用してテストをグループ化する方法を学習します。

Pytestでは、テスト機能でマーカーを使用できます。 マーカーは、さまざまな機能/属性を設定して機能をテストするために使用されます。 Pytestは、xfail、skip、およびparametrizeなどの多くの組み込みマーカーを提供します。 それとは別に、ユーザーは独自のマーカー名を作成できます。 マーカーは、以下に示す構文を使用してテストに適用されます-

@pytest.mark.<markername>

マーカーを使用するには、テストファイルにpytestモジュールを*インポートする必要があります。 テストに対して独自のマーカー名を定義し、それらのマーカー名を持つテストを実行できます。

マークされたテストを実行するには、次の構文を使用できます-

pytest -m <markername> -v

-m <markername>は、実行するテストのマーカー名を表します。

テストファイル test_compare.py および test_square.py を次のコードで更新します。 3つのマーカーを定義しています* –すばらしい、正方形、その他*。

test_compare.py

import pytest
@pytest.mark.great
def test_greater():
   num = 100
   assert num > 100

@pytest.mark.great
def test_greater_equal():
   num = 100
   assert num >= 100

@pytest.mark.others
def test_less():
   num = 100
   assert num < 200

test_square.py

import pytest
import math

@pytest.mark.square
def test_sqrt():
   num = 25
   assert math.sqrt(num) == 5

@pytest.mark.square
def testsquare():
   num = 7
   assert 7*7 == 40

@pytest.mark.others
   def test_equality():
   assert 10 == 11

今*その他*としてマークされたテストを実行するには、次のコマンドを実行します-

pytest -m others -v

以下の結果を参照してください。 others とマークされた2つのテストを実行しました。

test_compare.py::test_less PASSED
test_square.py::test_equality FAILED
============================================== FAILURES
==============================================
___________________________________________ test_equality
____________________________________________
   @pytest.mark.others
   def test_equality():
>  assert 10 == 11
E  assert 10 == 11
test_square.py:16: AssertionError
========================== 1 failed, 1 passed, 4 deselected in 0.08 seconds
==========================

同様に、他のマーカーでもテストを実行できます。

Pytest-フィクスチャ

フィクスチャは関数であり、適用される各テスト関数の前に実行されます。 フィクスチャは、データベース接続、テストするURL、入力データなどのテストにデータを供給するために使用されます。 したがって、すべてのテストで同じコードを実行する代わりに、フィクスチャ関数をテストに添付すると、各テストを実行する前に実行され、データがテストに返されます。

関数は、フィクスチャとしてマークされています-

@pytest.fixture

テスト関数は、フィクスチャー名を入力パラメーターとして指定することにより、フィクスチャーを使用できます。

ファイル test_div_by_3_6.py を作成し、以下のコードを追加します

import pytest

@pytest.fixture
def input_value():
   input = 39
   return input

def test_divisible_by_3(input_value):
   assert input_value % 3 == 0

def test_divisible_by_6(input_value):
   assert input_value % 6 == 0

ここに、テストに入力を提供する input_value という名前のフィクスチャ関数があります。 フィクスチャ関数にアクセスするには、テストではフィクスチャ名を入力パラメータとして指定する必要があります。

Pytestは、テストの実行中に、フィクスチャー名を入力パラメーターとして表示します。 次に、フィクスチャ関数を実行し、戻り値が入力パラメーターに保存されます。入力パラメーターはテストで使用できます。

次のコマンドを使用してテストを実行します-

pytest -k divisible -v

上記のコマンドは、次の結果を生成します-

test_div_by_3_6.py::test_divisible_by_3 PASSED
test_div_by_3_6.py::test_divisible_by_6 FAILED
============================================== FAILURES
==============================================
________________________________________ test_divisible_by_6
_________________________________________
input_value = 39
   def test_divisible_by_6(input_value):
>  assert input_value % 6 == 0
E  assert (39 % 6) == 0
test_div_by_3_6.py:12: AssertionError
========================== 1 failed, 1 passed, 6 deselected in 0.07 seconds
==========================

ただし、このアプローチには独自の制限があります。 テストファイル内で定義されたフィクスチャ関数は、テストファイル内にのみスコープを持ちます。 別のテストファイルでそのフィクスチャを使用することはできません。 フィクスチャを複数のテストファイルで使用できるようにするには、conftest.pyというファイルでフィクスチャ関数を定義する必要があります。 conftest.py については、次の章で説明します。

Pytest-Conftest.py

このファイルにフィクスチャ関数を定義して、複数のテストファイルからアクセスできるようにすることができます。

新しいファイル conftest.py を作成し、以下のコードを追加します-

import pytest

@pytest.fixture
def input_value():
   input = 39
   return input

フィクスチャ関数を削除するには、 test_div_by_3_6.py を編集します-

import pytest

def test_divisible_by_3(input_value):
   assert input_value % 3 == 0

def test_divisible_by_6(input_value):
   assert input_value % 6 == 0

新しいファイル test_div_by_13.py を作成します-

import pytest

def test_divisible_by_13(input_value):
   assert input_value % 13 == 0

これで、 conf_test.py で定義されたフィクスチャを利用する test_div_by_3_6.py および test_div_by_13.py ファイルができました。

次のコマンドを実行してテストを実行します-

pytest -k divisible -v

上記のコマンドは、次の結果を生成します-

test_div_by_13.py::test_divisible_by_13 PASSED
test_div_by_3_6.py::test_divisible_by_3 PASSED
test_div_by_3_6.py::test_divisible_by_6 FAILED
============================================== FAILURES
==============================================
________________________________________ test_divisible_by_6
_________________________________________
input_value = 39
   def test_divisible_by_6(input_value):
>  assert input_value % 6 == 0
E  assert (39 % 6) == 0
test_div_by_3_6.py:7: AssertionError
========================== 1 failed, 2 passed, 6 deselected in 0.09 seconds
==========================

テストは同じファイル内のフィクスチャを探します。 フィクスチャがファイルに見つからないため、conftest.pyファイルでフィクスチャをチェックします。 それを見つけると、フィクスチャメソッドが呼び出され、結果がテストの入力引数に返されます。

Pytest-テストのパラメーター化

テストのパラメーター化は、複数の入力セットに対してテストを実行するために行われます。 私たちは次のマーカーを使用してこれを行うことができます-

@pytest.mark.parametrize

以下のコードを test_multiplication.py というファイルにコピーします-

import pytest

@pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
def test_multiplication_11(num, output):
   assert 11*num == output

ここでは、テストは入力に11を乗算し、結果を期待される出力と比較します。 テストには4セットの入力があり、それぞれに2つの値があります。1つは11で乗算される数で、もう1つは期待される結果です。

次のコマンドを実行してテストを実行します-

Pytest -k multiplication -v

上記のコマンドは、次の出力を生成します-

test_multiplication.py::test_multiplication_11[1-11] PASSED
test_multiplication.py::test_multiplication_11[2-22] PASSED
test_multiplication.py::test_multiplication_11[3-35] FAILED
test_multiplication.py::test_multiplication_11[4-44] PASSED
============================================== FAILURES
==============================================
_________________ test_multiplication_11[3-35] __________________
num = 3, output = 35
   @pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
   def test_multiplication_11(num, output):
>  assert 11*num == output
E  assert (11 * 3) == 35
test_multiplication.py:5: AssertionError
============================== 1 failed, 3 passed, 8 deselected in 0.08 seconds
==============================

Pytest-Xfail/Skipテスト

この章では、PytestのSkipおよびXfailテストについて学習します。

今、以下の状況を考慮してください-

  • 何らかの理由により、テストはしばらくの間関連性がありません。
  • 新しい機能が実装されており、その機能のテストが既に追加されています。

これらの状況では、テストをxfailするか、テストをスキップするオプションがあります。

Pytestはxfailedテストを実行しますが、一部のテストが失敗または合格したとは見なされません。 これらのテストの詳細は、テストが失敗しても印刷されません(通常、pytestは失敗したテストの詳細を印刷することに注意してください)。 私たちは次のマーカーを使用してテストをxfailすることができます-

@pytest.mark.xfail

テストをスキップすると、テストは実行されません。 次のマーカーを使用してテストをスキップできます-

@pytest.mark.skip

後で、テストが適切になったら、マーカーを削除できます。

既にxfailとskipマーカーを含める必要がある test_compare.py を編集します-

import pytest
@pytest.mark.xfail
@pytest.mark.great
def test_greater():
   num = 100
   assert num > 100

@pytest.mark.xfail
@pytest.mark.great
def test_greater_equal():
   num = 100
   assert num >= 100

@pytest.mark.skip
@pytest.mark.others
def test_less():
   num = 100
   assert num < 200

次のコマンドを使用してテストを実行します-

pytest test_compare.py -v

実行すると、上記のコマンドは次の結果を生成します-

test_compare.py::test_greater xfail
test_compare.py::test_greater_equal XPASS
test_compare.py::test_less SKIPPED
============================ 1 skipped, 1 xfailed, 1 xpassed in 0.06 seconds
============================

Pytest-N回のテスト失敗後にテストスイートを停止する

実際のシナリオでは、コードの新しいバージョンを展開する準備ができたら、最初にプリプロダクション/ステージング環境に展開します。 次に、テストスイートが実行されます。

コードは、テストスイートに合格した場合にのみ、運用環境への展開に適しています。 テストが失敗した場合、それが1つであっても複数であっても、コードは実稼働に対応していません。

したがって、n個のテストが失敗した直後にテストスイートの実行を停止したい場合はどうでしょう。 これは、maxfailを使用してpytestで実行できます。

n個のテストが失敗した直後にテストスイートの実行を停止する構文は次のとおりです-

pytest --maxfail = <num>

次のコードを使用してファイルtest_failure.pyを作成します。

import pytest
import math

def test_sqrt_failure():
   num = 25
   assert math.sqrt(num) == 6

def test_square_failure():
   num = 7
   assert 7*7 == 40

def test_equality_failure():
   assert 10 == 11

このテストファイルを実行すると、3つのテストすべてが失敗します。 ここでは、1つの障害自体の後にテストの実行を停止します-

pytest test_failure.py -v --maxfail = 1
test_failure.py::test_sqrt_failure FAILED
=================================== FAILURES
=================================== _______________________________________
test_sqrt_failure __________________________________________
   def test_sqrt_failure():
   num = 25
>  assert math.sqrt(num) == 6
E  assert 5.0 == 6
E  + where 5.0 = <built-in function sqrt>(25)
E  + where <built-in function sqrt>= math.sqrt
test_failure.py:6: AssertionError
=============================== 1 failed in 0.04 seconds
===============================

上記の結果では、1つの障害で実行が停止していることがわかります。

Pytest-テストを並行して実行する

デフォルトでは、pytestは順番にテストを実行します。 実際のシナリオでは、テストスイートには多数のテストファイルがあり、各ファイルには多数のテストがあります。 これにより、実行時間が長くなります。 これを克服するために、pytestはテストを並行して実行するオプションを提供します。

このために、最初にpytest-xdistプラグインをインストールする必要があります。

次のコマンドを実行してpytest-xdistをインストールします-

pip install pytest-xdist

これで、構文 pytest -n <num> を使用してテストを実行できます

pytest -n 3

-n <num>は、複数のワーカーを使用してテストを実行します。ここでは3です。

実行するテストが数個しかない場合、時間差はあまりありません。 ただし、テストスイートが大きい場合は重要です。

XML形式のテスト実行結果

テスト実行の詳細をxmlファイルで生成できます。 このxmlファイルは、主にテスト結果を投影するダッシュボードがある場合に役立ちます。 そのような場合、xmlを解析して実行の詳細を取得できます。

test_multiplcation.pyからテストを実行し、次を実行してxmlを生成します。

pytest test_multiplication.py -v --junitxml="result.xml"

今、私たちはresult.xmlが次のデータで生成されるのを見ることができます-

<?xml version = "1.0" encoding = "utf-8"?>
<testsuite errors = "0" failures = "1"
name = "pytest" skips = "0" tests = "4" time = "0.061">
   <testcase classname = "test_multiplication"
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[1-11]"
      time = "0.00117516517639>
   </testcase>

   <testcase classname = "test_multiplication"
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[2-22]"
      time = "0.00155973434448">
   </testcase>

   <testcase classname = "test_multiplication"
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[3-35]" time = "0.00144290924072">
      failure message = "assert (11 * 3) == 35">num = 3, output = 35

         @pytest.mark.parametrize("num,
         output",[(1,11),(2,22),(3,35),(4,44)])

         def test_multiplication_11(num, output):>
         assert 11*num == output
         E assert (11 * 3) == 35

         test_multiplication.py:5: AssertionErro
      </failure>
   </testcase>
   <testcase classname = "test_multiplication"
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[4-44]"
      time = "0.000945091247559">
   </testcase>
</testsuite>

ここで、タグ <testsuit> は4つのテストがあり、失敗の数が1であることを要約しています。

  • タグ <testcase> は、実行された各テストの詳細を提供します。
  • <failure>タグは、失敗したテストコードの詳細を提供します。

Pytest-まとめ

このpytestチュートリアルでは、次の分野をカバーしました-

  • pytest ..のインストール
  • テストファイルとテスト機能の特定。
  • pytest –vを使用してすべてのテストファイルを実行します。
  • pytest <filename> -vを使用して特定のファイルを実行します。
  • pytest -k <substring> -vに一致するサブストリングによってテストを実行します。
  • マーカーpytest -m <marker_name> -vに基づいてテストを実行します。
  • @ pytest.fixtureを使用してフィクスチャを作成します。
  • conftest.pyでは、複数のファイルからフィクスチャにアクセスできます。
  • @ pytest.mark.parametrizeを使用したテストのパラメーター化。
  • @ pytest.mark.xfailを使用したXfailingテスト。
  • @ pytest.mark.skipを使用したテストのスキップ。
  • pytest --maxfail = <num>を使用して、n個の失敗でテスト実行を停止します。
  • pytest -n <num>を使用してテストを並行して実行します。
  • pytest -v --junitxml = "result.xml"を使用して結果xmlを生成します。

Pytest-結論

このチュートリアルでは、pytestフレームワークを紹介しました。 これで、pytestを使用してテストの作成を開始できるはずです。

良い習慣として-

  • テストする機能/モジュールに基づいて、異なるテストファイルを作成します。
  • テストファイルとメソッドに意味のある名前を付けます。
  • さまざまな基準に基づいてテストをグループ化するのに十分なマーカーがあります。
  • 必要なときにいつでも器具を使用してください。