2017-10-16 34 views

答えて

1

私はずっと前にこの問題を検討していましたが、自己解決の方が良いとの結論に達しました。

私のプラグインはpytestプロセス全体を終了させて​​いましたが、単一の(現在の)テストだけが失敗するように調整することができます。ここでは、調整案されて:あなたは、各試験時間が原因プリセットアラームに個別kill -ALRM $pid場合、またはを行うと、唯一の現在のテストは

import pytest 
import signal 


class Termination(SystemExit): 
    pass 


class TimeoutExit(BaseException): 
    pass 


def _terminate(signum, frame): 
    raise Termination("Runner is terminated from outside.") 


def _timeout(signum, frame): 
    raise TimeoutExit("Runner timeout is reached, runner is terminating.") 


@pytest.hookimpl 
def pytest_addoption(parser): 
    parser.addoption(
     '--timeout', action='store', dest='timeout', type=int, default=None, 
     help="number of seconds before each test failure") 


@pytest.hookimpl 
def pytest_configure(config): 
    # Install the signal handlers that we want to process. 
    signal.signal(signal.SIGTERM, _terminate) 
    signal.signal(signal.SIGALRM, _timeout) 


@pytest.hookimpl(hookwrapper=True) 
def pytest_runtest_protocol(item, nextitem): 

    # Set the per-test timeout (an alarm signal). 
    if item.config.option.timeout is not None: 
     signal.alarm(item.config.option.timeout) 

    try: 
     # Run the setup, test body, and teardown stages. 
     yield 
    finally: 
     # Disable the alarm when the test passes or fails. 
     # I.e. when we get into the framework's body. 
     signal.alarm(0) 

失敗しますが、他のテストは継続されます。

このTimeoutExitは、BaseExceptionから継承されているため、except Exception: passのライブラリでは表示されません。

したがって、この側面ではSystemExitです。しかし、SystemExitまたはKeyboardInterruptionとは異なり、pytestはそれをキャッチせず、そのような例外で終了しません。

time.sleep(...)(信号のように)を行っても、アラームの瞬間にテストが実行されるどこにでも例外が注入されます。

プロセスには1つのアラーム(OS制限)しか設定できないことに注意してください。また、同じ目的でALRM信号も使用するため、pytest-timeoutと互換性がありません。

&テストごとのタイムアウトを設定する場合は、スマートアラームマネージャを実装する必要があります。スマートアラームマネージャは、ほとんどのアラームを追跡し、OSアラームを最も早く設定し、アラーム信号が受信されます。場合


、あなたがkill -TERM $pidまたはちょうどkill $pid(優雅な終了を)やる、それが直ちに終了されます - それはBaseExceptionであり、通常のコードまたはpytestでキャッチされていないSystemExitから継承するため。

後者のケースは、異なる反応をさまざまな信号に設定する方法の大部分を示しています。 USR1 & USR2と他のキャッチ可能な信号でも同様のことができます。クイックテストについて


conftest.pyファイル(擬似プラグイン)に上記プラグインコードを置きます。

このテストファイル考えてみましょう:タイムアウトなしpytestを実行

import time 

def test_this(): 
    try: 
     time.sleep(10) 
    except Exception: 
     pass 

def test_that(): 
    pass 

は何もしない、との両方のテストに合格:タイムアウトでそれを実行する

$ pytest -s -v 
......... 
collected 2 items                                         

test_me.py::test_this PASSED 
test_me.py::test_that PASSED 

======= 2 passed in 10.02 seconds ======= 

は最初のテストに失敗しますが、2番目に合格します1つ:

$ pytest -s -v --timeout=5 
......... 
collected 2 items                                         

test_me.py::test_this FAILED 
test_me.py::test_that PASSED 

============== FAILURES ============== 
______________ test_this _____________ 

    def test_this(): 
     try: 
>   time.sleep(10) 

test_me.py:5: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signum = 14, frame = <frame object at 0x106b3c428> 

    def _timeout(signum, frame): 
>  raise TimeoutExit("Runner timeout is reached, runner is terminating.") 
E  conftest.pytest_configure.<locals>.TimeoutExit: Runner timeout is reached, runner is terminating. 

conftest.py:24: TimeoutExit 
======= 1 failed, 1 passed in 5.11 seconds ======= 
+0

私は時間があったとすれば、実装の詳細を深く掘り下げるとは思いませんが、これはiです本当に啓発です!私はそれを参考にしておきます。 – JCode

関連する問題