根据执行时间通过测试

Pass a test based on its execution time

pytest有类似计时器测试的东西吗?

@pytest.mark.timer(60)
def test_this_code_runs_in_less_than_x():
    bla()

如果 bla 执行超过 60 秒,哪个会失败?

我可以用我自己的装饰器轻松实现这个,例如:

import time, threading                                                                                                                                                                                                     
def timeout(func):                                                                                                                                                                                              
    def wrapper():                                                                                                                                                                                              
        start_time = time.time()                                                                                                                                                                                
        timeout = start_time + 1                                                                                                                                                                                
                                                                                                                                                                                                                
        th = threading.Thread(target=func)                                                                                                                                                                      
        th.start()                                                                                                                                                                                              
        while time.time() < timeout and th.isAlive():                                                                                                                                                           
            pass                                                                                                                                                                                                
        if th.isAlive():                                                                                                                                                                                        
            raise TimeoutError()                                                                                                                                                                                
        th.join()                                                                                                                                                                                               
                                                                                                                                                                                                                
    return wrapper                                                                                                                                                                                              
                                                                                                                                                                                                                
                                                                                                                                                                                                                
@timeout                                                                                                                                                                                                        
def _test():                                                                                                                                                                                                    
    time.sleep(2)                                                                                                                                                                                               
                                                                                                                                                                                                                
                                                                                                                                                                                                                
def test_should_fail_after_one_second():                                                                                                                                                                        
    _test() 

但我不想发明轮子...

我知道 pytest 可以有一个 --timeout 参数,但我正在寻找一些东西作为测试定义的一部分,而不是影响所有测试的可配置参数

使用 pytest-timeout 插件,您可以用超时时间标记单个测试,以秒为单位:

@pytest.mark.timeout(60)
def test_foo():
    pass

您可以通过向装饰器添加 method 参数在以下两种“线程方法”之间明确选择:

  • thread:在单独的线程中运行睡眠,并在达到超时时终止测试进程。请注意,这可能会导致正常 JUnit XML 输出或 fixture 拆卸出现问题。
  • signal:安排 SIGALRM 警报,在达到超时时取消测试。这允许您的测试 运行 正常完成。但是,如果您的代码已经使用 SIGALRM,这可能会影响其正常功能。

如果您的系统支持signal.SIGALRM(通常是Unix),默认使用signal线程方法。否则,将使用 thread 方法。