2017-10-16 8 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은 에서 상속되기 때문에 except Exception: pass 인 라이브러리에 의해 표시되지 않습니다.

따라서이 부분은 모두 SystemExit입니다. 그러나 SystemExit 또는 KeyboardInterruption과 달리 pytest는이를 catch하지 않으며 이러한 예외가 발생하면 종료하지 않습니다.

time.sleep(...) (모든 신호와 동일)이더라도 알람이 울릴 때마다 테스트가 수행되는 곳으로 예외가 주입됩니다.

프로세스 (OS 제한)에 대해 하나의 단일 알람 만 설정할 수 있음을 기억하십시오. 또한 같은 목적으로 ALRM 신호를 사용하기 때문에 pytest-timeout과 호환되지 않습니다.

글로벌 단위로 테스트 시간 초과를 사용하려면 스마트 알람 관리자를 구현해야합니다 알람 신호가 수신됩니다. 경우


, 당신은 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 ======= 

는 첫 번째 테스트 실패,하지만 두 번째 통과 하나 :

$ 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

구현 세부 정보를 너무 자세히 파고 들지는 않았지만이 경우 정말 계몽! 저는 이것을 참고 자료로 사용할 것입니다. – JCode