web-dev-qa-db-ja.com

PyTestのassertステートメントの動作をPython

私はPython assertステートメントを使用して、実際の動作と予想される動作を一致させています。エラーテストケースが中断するかのようにこれらを制御することはできません。アサーションエラーを制御し、失敗のアサートでテストケースを中止するかどうかを定義したい。

また、アサーションエラーが発生した場合など、テストケースを一時停止してユーザーがいつでも再開できるようにすることもできます。

私はこれを行う方法がわかりません

コード例、ここではpytestを使用しています

import pytest
def test_abc():
    a = 10
    assert a == 10, "some error message"

Below is my expectation

AssertがassertionErrorをスローする場合、テストケースを一時停止するオプションが必要で、デバッグして後で再開できます。一時停止と再開には、tkinterモジュールを使用します。以下のようにアサート機能を作成します

import tkinter
import tkinter.messagebox

top = tkinter.Tk()

def _assertCustom(assert_statement, pause_on_fail = 0):
    #assert_statement will be something like: assert a == 10, "Some error"
    #pause_on_fail will be derived from global file where I can change it on runtime
    if pause_on_fail == 1:
        try:
            eval(assert_statement)
        except AssertionError as e:
            tkinter.messagebox.showinfo(e)
            eval (assert_statement)
            #Above is to raise the assertion error again to fail the testcase
    else:
        eval (assert_statement)

今後は、この関数を使用してすべてのassertステートメントを変更する必要があります

import pytest
def test_abc():
    a = 10
    # Suppose some code and below is the assert statement 
    _assertCustom("assert a == 10, 'error message'")

アサートを使用した何千もの場所で変更を行わなければならないので、これは私にとってあまりにも多くの努力です。 pytestでそれを行う簡単な方法はありますか

Summary:失敗時にテストケースを一時停止し、デバッグ後に再開できるものが必要です。私はtkinterについて知っており、それが私がそれを使用した理由です。他のアイデアは歓迎されます

Note:上記のコードはまだテストされていません。小さな構文エラーもあるかもしれません

編集:回答をありがとう。この質問を少し先に拡張します。アサートの動作を変更したい場合はどうすればよいですか。現在、アサーションエラーがある場合、テストケースが終了します。特定のアサートエラーでテストケースの終了が必要かどうかを選択したい場合はどうすればよいですか。上記のようにカスタムアサート関数を記述したくないのは、この方法で多くの場所で変更する必要があるためです。

18
Nitesh

pytest --pdb を使用すると、コードをまったく変更しなくても、希望どおりの結果を得ることができます。

あなたの例で:

import pytest
def test_abc():
    a = 9
    assert a == 10, "some error message"

--pdbで実行:

py.test --pdb
collected 1 item

test_abc.py F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    def test_abc():
        a = 9
>       assert a == 10, "some error message"
E       AssertionError: some error message
E       assert 9 == 10

test_abc.py:4: AssertionError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /private/tmp/a/test_abc.py(4)test_abc()
-> assert a == 10, "some error message"
(Pdb) p a
9
(Pdb)

テストが失敗するとすぐに、組み込みのpythonデバッガーでデバッグできます。デバッグが完了したら、残りのテストでcontinueできます。

7
gnvk

PyCharmを使用している場合は、例外ブレークポイントを追加して、アサートが失敗したときに実行を一時停止できます。ブレークポイントの表示(CTRL-SHIFT-F8)を選択し、AssertionErrorのオンレイズ例外ハンドラーを追加します。これにより、テストの実行が遅くなる場合があることに注意してください。

それ以外の場合、アサーションが失敗した時点ではなく、失敗した各テストの(エラーが発生する直前に)endで一時停止してもかまいません。いくつかのオプションがあります。ただし、この時点で、テストで開かれたファイルを閉じるなど、さまざまなクリーンアップコードが既に実行されている可能性があることに注意してください。可能なオプションは次のとおりです。

  1. -pdbオプション を使用して、エラー時にデバッガーにドロップするようにpytestに指示できます。

  2. 次のデコレータを定義して、関連する各テスト関数をそれでデコレートできます。 (メッセージのロギングとは別に、この時点で pdb.post_mortem を開始することもできます。または、例外が発生したフレームのローカルでインタラクティブな code.interact を開始することもできます、 この答え で説明されているように)

from functools import wraps

def pause_on_assert(test_func):
    @wraps(test_func)
    def test_wrapper(*args, **kwargs):
        try:
            test_func(*args, **kwargs)
        except AssertionError as e:
            tkinter.messagebox.showinfo(e)
            # re-raise exception to make the test fail
            raise
    return test_wrapper

@pause_on_assert
def test_abc()
    a = 10
    assert a == 2, "some error message"

  1. すべてのテスト関数を手動で装飾したくない場合は、代わりに sys.last_value を検査する自動使用フィクスチャを定義できます。
import sys

@pytest.fixture(scope="function", autouse=True)
def pause_on_assert():
    yield
    if hasattr(sys, 'last_value') and isinstance(sys.last_value, AssertionError):
        tkinter.messagebox.showinfo(sys.last_value)
4
Uri Granta

簡単な解決策の1つは、Visual Studio Codeを使用する場合、 条件付きブレークポイント を使用することです。

これにより、たとえば次のようにアサーションを設定できます。

import pytest
def test_abc():
    a = 10
    assert a == 10, "some error message"

次に、アサーション行に条件付きブレークポイントを追加して、アサーションが失敗した場合にのみブレークするようにします。

enter image description here

4
Nick Martin