Pytest-クイックガイド

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

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は、これらのファイルをテストファイルとして自動的に識別します。私達can 明示的に言及することにより、pytestに他のファイル名を実行させます。

Pytestでは、テスト関数名がで始まる必要があります test。形式ではない関数名test*pytestではテスト関数とは見なされません。私達cannot 明示的にpytestにで始まらない関数を考慮させる test テスト機能として。

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

それでは、最初の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が40と等しいかどうかが比較されていますが、これは誤りです。最後に、テスト実行の概要を確認できます。1つは失敗し、1つは合格です。

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

ここで、以下のコマンドを実行して、結果をもう一度確認します-

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 
=================================

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

Note − pytestコマンドは、フォーマットのすべてのファイルを実行します test_* または *_test 現在のディレクトリとサブディレクトリにあります。

この章では、単一のテストファイルと複数のテストファイルを実行する方法を学習します。すでにテストファイルがあります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.py そして test_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

これにより、単語を含むすべてのテスト名が実行されます ‘great’その名前で。この場合、彼らは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 それらの中で。

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

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

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

@pytest.mark.<markername>

マーカーを使用するには、 import pytestテストファイル内のモジュール。テストに独自のマーカー名を定義し、それらのマーカー名を持つテストを実行できます。

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

pytest -m <markername> -v

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

テストファイルを更新します test_compare.py そして test_square.py次のコードで。3つのマーカーを定義しています– great, square, others

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

次に、としてマークされたテストを実行します others、次のコマンドを実行します-

pytest -m others -v

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

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
==========================

同様に、他のマーカーを使用してテストを実行することもできます–すばらしい、比較

フィクスチャは関数であり、適用される各テスト関数の前に実行されます。フィクスチャは、データベース接続、テストする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 次の章で説明します。

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

新しいファイルを作成する 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

これで、ファイルができました test_div_by_3_6.py そして test_div_by_13.py で定義されたフィクスチャを利用する conftest.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.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のSkipテストとXfailテストについて学習します。

ここで、以下の状況を考えてみましょう-

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

このような状況では、テストにxfailするか、テストをスキップするかを選択できます。

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

@pytest.mark.xfail

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

@pytest.mark.skip

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

編集する test_compare.py すでにxfailマーカーとスキップマーカーを含める必要があります-

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
============================

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

コードは、テストスイートに合格した場合にのみ、本番環境にデプロイする資格があります。テストが失敗した場合、それが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-xdistプラグインをインストールする必要があります。

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

pip install pytest-xdist

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

pytest -n 3

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

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

テスト実行の詳細を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 –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を使用してテストの作成を開始できるようになります。

グッドプラクティスとして-

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