1 pytest自动化测试 - 我对测试用例超时处理的一点看法
1.1 背景
用例在执行过程中,可能由于网络等待,或者等待一些特殊的文件,而又由于一些异常,导致这些条件一直不能满足,用例卡死,这种情况在自动化测试中是不允许的,会浪费大量的时间,影响测试任务的进度,甚至导致版本发布周期的延长。
为了给每个用例都设置上超时时间,有以下几种方法:
1.2 方法1:给每个用例添加@pytest.mark.timeout
修饰器
@pytest.mark.timeout在Windows下并不能很好的工作,1 个用例出现超时,整个测试任务就中断了,非常扯淡!
import pytest
import time
@pytest.mark.timeout(5)
def test_case1():
time.sleep(2)
assert True
@pytest.mark.timeout(5)
def test_case2():
time.sleep(6) # 此用例会超时
assert True
def test_case3():
print("用例3:Windows下不会执行")
assert 3 == 3
1.3 方法2:使用钩子函数给每个用例添加一个timeout修饰器
然而,下面这个做法,在Windows下并没有什么卵用!,超时的那个用例也执行成功了!
import pytest
import time
def pytest_collection_modifyitems(session, config, items):
for item in items:
item.add_marker(pytest.mark.timeout(3))
def setup_function():
print()
def test_case3():
print("用例3:开始")
time.sleep(3)
assert True
print("用例3:结束")
def test_case4():
print("用例4:开始")
time.sleep(5) # 此用例会超时,但Windows不超时,神奇!
assert True
print("用例4:结束")
def test_case5():
print("用例5: 开始")
assert 3 == 3
print("用例5: 结束")
Windows下的执行结果:
============================= test session starts =============================
platform win32 -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
rootdir: D:\TYYSOFT\Study\Python\pytest
configfile: pytest.ini
plugins: check-2.4.1, html-4.1.1, metadata-3.1.1, timeout-2.3.1, xdist-3.6.1
collected 3 items
test_timeout_004.py
用例3:开始
用例3:结束
.
用例4:开始
用例4:结束
.
用例5: 开始
用例5: 结束
.
-- Generated html report: file:///D:/TYYSOFT/Study/Python/pytest/report.html --
============================== 3 passed in 8.03s ==============================
其他所谓的使用timeout
标记的超时处理在Windows下都没有什么卵用!
1.4 方法3:介绍一个自己写的使用线程处理用例超时的方法
用例的超时,其实主要是监控每条任务的超时情况,通过创建1个基础函数base_func
这个函数每次调用时都创建1个线程,并给线程设置超时时间,用例中的执行语句都通过这个线程函数base_func
来执行,base_func
中对超时任务会设置失败。
import pytest
import threading
import time
# 核心函数:该函数创建1个线程,并执行给定的task,超时后会把用例设置为失败
def base_func(task, timeout=5):
thread = threading.Thread(target=task)
thread.start()
thread.join(timeout) #设置超时
if thread.is_alive():
print(f"::{task.__name__}: 语句执行超时...")
assert False
# 1个长时间任务
def long_time_task():
time.sleep(2)
# 模块发送消息的基础函数
def send_msg(msg):
print(msg)
# 预置条件
def setup_function():
print()
base_func(print("预置条件!"))
# 这是用例1
def test_timeout_001():
base_func(send_msg("用例1开始"))
base_func(long_time_task)
base_func(send_msg("用例1结束"))
def test_timeout_002():
base_func(send_msg("用例2开始"))
base_func(send_msg("用例2结束"))
输出结果:
============================= test session starts =============================
platform win32 -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
rootdir: D:\TYYSOFT\Study\Python\pytest
configfile: pytest.ini
plugins: check-2.4.1, html-4.1.1, metadata-3.1.1, timeout-2.3.1, xdist-3.6.1
collected 2 items
test_timeout_002.py
预置条件!
用例1开始
::long_time_task: 语句执行超时...
F
预置条件!
用例2开始
用例2结束
.
================================== FAILURES ===================================
______________________________ test_timeout_001 _______________________________
def test_timeout_001():
base_func(send_msg("用例1开始"))
> base_func(long_time_task)
test_timeout_002.py:31:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
task = <function long_time_task at 0x000001AAE4112DE0>, timeout = 5
def base_func(task, timeout=5):
thread = threading.Thread(target=task)
thread.start()
thread.join(timeout) #设置超时
if thread.is_alive():
print(f"::{task.__name__}: 语句执行超时...")
> assert False
E assert False
test_timeout_002.py:13: AssertionError
-- Generated html report: file:///D:/TYYSOFT/Study/Python/pytest/report.html --
=========================== short test summary info ===========================
FAILED test_timeout_002.py::test_timeout_001 - assert False
========================= 1 failed, 1 passed in 5.11s =========================
两个用例都执行了, 第2个用例并没有因为第1个用例超时而中止执行!
使用基础函数来包装测试执行语句的必要性, 因为实际在测试执行时, 每个语句都有可能执行超时,对其进行封装执行可以保证测试脚本的严谨性。
作者声明:本文用于记录和分享作者的学习心得,可能有部分文字或示例来自AI平台,如:豆包、DeepSeek(硅基流动) (注册链接)等,由于本人水平有限,难免存在表达错误,欢迎留言交流和指教!
Copyright © 2022~2025 All rights reserved.