pytest 是一个非常灵活且强大的测试框架,它支持简单的单元测试到复杂的功能测试。显著特点是其简洁的语法,可以无需继承 TestCase 类直接使用函数来编写测试用例,并通过 assert语句 进行断言。还支持参数化测试、丰富的插件系统。
pytest自动化测试框架速成,1小时入门
本系列探讨一下如何基于 pytest 构建自动化测试套件。
PS: 本文基于pytest 8.3.3
安装 pytest
在终端中安装:
pip install -U pytest
测试用例和断言
pytest 的设计思想围绕测试用例的发现、执行、管理和报告展开,其灵活性和可扩展性也主要服务于测试用例的高效编写和维护。
测试用例需要编写在前缀为名称 test_ 或 test 的模块(.py文件)中,作为测试用例的函数的前缀也需为 test 或 _test。每个测试用例中都需要至少一个断言(assert)。比如:
# test_mod.py
list_list = 'hello!'
def test_list_fail():
assert 'hello1!' == list_list, "两个值不同"
def test_list_pass():
assert 'hello!' == list_list, "两个值不同"
test_list_fail 和 test_list_pass 皆是测试用例。
assert 后接两个参数,第一个值用于判断,第二个值是字符串。第一个值为 True(真) ,则该测试用例继续进行直至结束;如果为 False(假) ,则测试失败,并且 pytest 会停止执行该测试用例、报告错误并打印第二个值。
第一个值可以是表达式、函数返回值、数值、布尔值等等,第二个值可以自定义信息,精准描述问题。
test_list_fail 和 test_list_pass 两个测试用例的结果如下:
===================================================================== test session starts ======================================================================
collected 2 items
Test/test_mod1.py::test_list_fail FAILED [ 50%]
Test/test_mod1.py::test_list_pass PASSED [100%]
=========================================================================== FAILURES ===========================================================================
________________________________________________________________________ test_list_fail ________________________________________________________________________
def test_list_fail():
> assert 'hello1!' == list_list, "两个值不同"
E AssertionError: 两个值不同
E assert 'hello1!' == 'hello!'
E
E - hello!
E + hello1!
E ? +
Test\test_mod1.py:7: AssertionError
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_list_fail - AssertionError: 两个值不同
================================================================= 1 failed, 1 passed in 0.07s ==================================================================
test_mod.py::test_list_fail FAILED 表示测试用例 test_list_fail 断言失败,测试用例未通过 。
test_mod.py::test_list_pass PASSED 表示测试用例 test_hanshu、test_list 断言成功,测试用例通过。
做下补充,第一个值可以如下:
- 比较表达式
# 等于
assert 10 == 5 # False
# 不等于
assert 10 != 5 # True
# 大于
assert 10 > 5 # True
# 小于
assert 10 < 5 # False
# 大于等于
assert 10 >= 5 # True
# 小于等于
assert 10 <= 5 # False
- 逻辑表达式
# 逻辑与
assert (10 > 5) and (5 < 10) # True
# 逻辑或
assert (10 > 5) or (5 > 10) # True
# 逻辑非
assert not (10 > 5) # False
- 成员表达式
# in 操作符
assert 5 in [1, 2, 3, 4, 5] # True
# not in 操作符
assert 6 not in [1, 2, 3, 4, 5] # True
- 身份表达式
a = [1, 2, 3]
b = [1, 2, 3]
c = a
# is 操作符
assert a is c # True,因为 a 和 c 引用同一个对象
# is not 操作符
assert a is not b # True,因为 a 和 b 是不同的对象
- 布尔值的隐式转换
# 空列表、空字符串、零等会被视为 False,而非空列表、非空字符串、非零等会被视为 True
# 空列表
assert [] # False
# 非空列表
assert [1, 2, 3] # True
# 空字符串
assert "" # False
# 非空字符串
assert "Hello" # True
# 零
assert 0 # False
# 非零
assert 10 # True
- 布尔值
# True
assert True
# False
assert False
测试用例中还可以有多个断言,任意断言失败,不再执行该测试用例,判定失败:
def test_case1():
assert True, "成功"
assert True, "成功"
assert True, "成功"
def test_case2():
assert True, "成功"
assert False, "失败"
assert True, "成功"
运行结果:
===================================================================== test session starts ======================================================================
collected 2 items
Test/test_mod1.py::test_case1 PASSED [ 50%]
Test/test_mod1.py::test_case2 FAILED [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_case2 __________________________________________________________________________
def test_case2():
assert True, "成功"
> assert False, "失败"
E AssertionError: 失败
E assert False
Test\test_mod1.py:9: AssertionError
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_case2 - AssertionError: 失败
================================================================= 1 failed, 1 passed in 0.07s ==================================================================
测试用例组
应用有许多模块,每个模块的测试用例我们都可以写在对应模块文件里。模块又有很多功能,我们又如何对功能进行划分呢?
pytest 框架里有测试组概念,用类(class)表达,可以在类里编写功能的所有测试用例。
# C:\PythonTest\Test\test_mod.py
class TestCaseGroup:
@staticmethod
def test_case1():
x = "this"
assert "h" in x, "字符串中没有 h"
@staticmethod
def test_case2():
x = 1
y = 2
assert type(x) == type(y), "x 不等于 y"
运行结果:
===================================================================== test session starts ======================================================================
collected 2 items
Test/test_mod1.py::TestCaseGroup::test_case1 PASSED [ 50%]
Test/test_mod1.py::TestCaseGroup::test_case2 FAILED [100%]
=========================================================================== FAILURES ===========================================================================
___________________________________________________________________ TestCaseGroup.test_case2 ___________________________________________________________________
@staticmethod
def test_case2():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::TestCaseGroup::test_case2 - AssertionError: x 不等于 y
================================================================= 1 failed, 1 passed in 0.07s ==================================================================
运行测试用例
编写测试用例后,可以在命令行中运行测试用例。以 Windows 为例:
- 终端中运行 C:\PythonTest\Test\test_mod.py 中所有测试用例:
pytest -v C:\PythonTest\Test\test_mod.py
- 终端中运行 C:\PythonTest\Test\test_mod.py 中的 test_list_fail 测试用例:
pytest -v C:\PythonTest\Test\test_mod.py::test_list_fail
- 在终端中运行 C:\PythonTest\Test\test_mod.py 中的 TestAdd 测试用例组:
pytest -v C:\PythonTest\Test\test_mod.py::TestClassOne
- 在终端中运行 C:\PythonTest\Test\test_mod.py 中 TestAdd 中的 test_error 测试用例:
pytest -v C:\PythonTest\Test\test_mod.py::TestClassOne::test_error
控制输出信息
pytest 提供许多命令行参数来控制输出的信息,我挑几个自认为有价值的说一下。
参数 -v
首先定义一组测试用例:
# test_mod1.py
def test_case1():
x = "this"
assert "h" in x, "字符串中没有 h"
def test_case2():
x = 1
y = 2
assert type(x) != type(y), "x 不等于 y"
def test_case3():
x = "this"
assert "h" in x, "字符串中没有 h"
- 不带 -v 参数:
===================================================================== test session starts ======================================================================
collected 3 items
Test\test_mod1.py .F. [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_case2 __________________________________________________________________________
def test_case2():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:11: AssertionError
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_case2 - AssertionError: x 不等于 y
================================================================= 1 failed, 2 passed in 0.07s ==================================================================
. 表示通过,F 表示不通过,按顺序显示。
- 带 -v 参数:
===================================================================== test session starts ======================================================================
collected 3 items
Test/test_mod1.py::test_case1 PASSED [ 33%]
Test/test_mod1.py::test_case2 FAILED [ 66%]
Test/test_mod1.py::test_case3 PASSED [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_case2 __________________________________________________________________________
def test_case2():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:11: AssertionError
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_case2 - AssertionError: x 不等于 y
================================================================= 1 failed, 2 passed in 0.07s ==================================================================
显示详细的测试执行信息,包括每个测试用例的完整名称(模块名、类名、方法名)和结果。
参数 -r
这个参数主要控制 short test summary info 里的信息输出。可以与 -v 一起使用,如 -vra。
首先定义一组测试用例:
# test_mod1.py
import pytest
def test_pass():
x = "this"
assert "h" in x, "字符串中没有 h"
def test_fail():
x = 1
y = 2
assert type(x) != type(y), "x 不等于 y"
def test_pass1():
x = "this"
assert "h" in x, "字符串中没有 h"
@pytest.mark.xfail(reason="xfail")
def test_xfail():
x = 1
y = 2
assert type(x) != type(y), "x 不等于 y"
@pytest.mark.skip(reason="skip")
def test_skip():
x = 1
y = 2
assert type(x) != type(y), "x 不等于 y"
- -rf:输出断言失败的测试用例
是 pytest 的默认值,如果不使用 -r 系列参数,默认就是 -rf(-vrf 等价于 -v)。
===================================================================== test session starts ======================================================================
collected 5 items
Test/test_mod1.py::test_pass PASSED [ 20%]
Test/test_mod1.py::test_fail FAILED [ 40%]
Test/test_mod1.py::test_pass1 PASSED [ 60%]
Test/test_mod1.py::test_xfail XFAIL (xfail) [ 80%]
Test/test_mod1.py::test_skip SKIPPED (skip) [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_fail ___________________________________________________________________________
def test_fail():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_fail - AssertionError: x 不等于 y
====================================================== 1 failed, 2 passed, 1 skipped, 1 xfailed in 0.08s =======================================================
- -ra:输出除断言成功之外的所有测试用例
===================================================================== test session starts ======================================================================
collected 5 items
Test/test_mod1.py::test_pass PASSED [ 20%]
Test/test_mod1.py::test_fail FAILED [ 40%]
Test/test_mod1.py::test_pass1 PASSED [ 60%]
Test/test_mod1.py::test_xfail XFAIL (xfail) [ 80%]
Test/test_mod1.py::test_skip SKIPPED (skip) [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_fail ___________________________________________________________________________
def test_fail():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
=================================================================== short test summary info ====================================================================
SKIPPED [1] Test\test_mod1.py:24: skip
XFAIL Test/test_mod1.py::test_xfail - xfail
FAILED Test/test_mod1.py::test_fail - AssertionError: x 不等于 y
====================================================== 1 failed, 2 passed, 1 skipped, 1 xfailed in 0.08s =======================================================
- -rA:输出所有的测试用例
===================================================================== test session starts ======================================================================
collected 5 items
Test/test_mod1.py::test_pass PASSED [ 20%]
Test/test_mod1.py::test_fail FAILED [ 40%]
Test/test_mod1.py::test_pass1 PASSED [ 60%]
Test/test_mod1.py::test_xfail XFAIL (xfail) [ 80%]
Test/test_mod1.py::test_skip SKIPPED (skip) [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_fail ___________________________________________________________________________
def test_fail():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
============================================================================ PASSES ============================================================================
=================================================================== short test summary info ====================================================================
PASSED Test/test_mod1.py::test_pass
PASSED Test/test_mod1.py::test_pass1
SKIPPED [1] Test\test_mod1.py:24: skip
XFAIL Test/test_mod1.py::test_xfail - xfail
FAILED Test/test_mod1.py::test_fail - AssertionError: x 不等于 y
====================================================== 1 failed, 2 passed, 1 skipped, 1 xfailed in 0.08s =======================================================
- -rp:输出断言成功的测试用例
===================================================================== test session starts ======================================================================
collected 5 items
Test/test_mod1.py::test_pass PASSED [ 20%]
Test/test_mod1.py::test_fail FAILED [ 40%]
Test/test_mod1.py::test_pass1 PASSED [ 60%]
Test/test_mod1.py::test_xfail XFAIL (xfail) [ 80%]
Test/test_mod1.py::test_skip SKIPPED (skip) [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_fail ___________________________________________________________________________
def test_fail():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
=================================================================== short test summary info ====================================================================
PASSED Test/test_mod1.py::test_pass
PASSED Test/test_mod1.py::test_pass1
====================================================== 1 failed, 2 passed, 1 skipped, 1 xfailed in 0.08s =======================================================
- -rx:输出被 @pytest.mark.xfail 装饰的测试用例
===================================================================== test session starts ======================================================================
collected 5 items
Test/test_mod1.py::test_pass PASSED [ 20%]
Test/test_mod1.py::test_fail FAILED [ 40%]
Test/test_mod1.py::test_pass1 PASSED [ 60%]
Test/test_mod1.py::test_xfail XFAIL (xfail) [ 80%]
Test/test_mod1.py::test_skip SKIPPED (skip) [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_fail ___________________________________________________________________________
def test_fail():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
=================================================================== short test summary info ====================================================================
XFAIL Test/test_mod1.py::test_xfail - xfail
====================================================== 1 failed, 2 passed, 1 skipped, 1 xfailed in 0.07s =======================================================
- -rs:输出被 @pytest.mark.skip 装饰的测试用例
===================================================================== test session starts ======================================================================
collected 5 items
Test/test_mod1.py::test_pass PASSED [ 20%]
Test/test_mod1.py::test_fail FAILED [ 40%]
Test/test_mod1.py::test_pass1 PASSED [ 60%]
Test/test_mod1.py::test_xfail XFAIL (xfail) [ 80%]
Test/test_mod1.py::test_skip SKIPPED (skip) [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_fail ___________________________________________________________________________
def test_fail():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
=================================================================== short test summary info ====================================================================
SKIPPED [1] Test\test_mod1.py:24: skip
====================================================== 1 failed, 2 passed, 1 skipped, 1 xfailed in 0.07s =======================================================
- -rN:不输出任何内容
===================================================================== test session starts ======================================================================
collected 5 items
Test/test_mod1.py::test_pass PASSED [ 20%]
Test/test_mod1.py::test_fail FAILED [ 40%]
Test/test_mod1.py::test_pass1 PASSED [ 60%]
Test/test_mod1.py::test_xfail XFAIL (xfail) [ 80%]
Test/test_mod1.py::test_skip SKIPPED (skip) [100%]
=========================================================================== FAILURES ===========================================================================
__________________________________________________________________________ test_fail ___________________________________________________________________________
def test_fail():
x = 1
y = 2
> assert type(x) != type(y), "x 不等于 y"
E AssertionError: x 不等于 y
E assert <class 'int'> != <class 'int'>
E + where <class 'int'> = type(1)
E + and <class 'int'> = type(2)
Test\test_mod1.py:13: AssertionError
====================================================== 1 failed, 2 passed, 1 skipped, 1 xfailed in 0.07s =======================================================
参数 --tb
用于设置测试失败时输出的 FAILURES 信息的错误堆栈信息的详细程度和格式。可以与 -v 一起使用,如 -v --tb=no。
首先定义一组测试用例:
# test_mod1.py
def test_01():
assert "a" == "b"
def test_02():
assert "a" == "b"
def test_03():
assert "a" == "b"
- --tb=auto:默认值
官方文档中说只输出第一条与最后一条测试用例,但是测试下来与 --tb=long 一致。这里说明一下,输出效果如下。
===================================================================== test session starts ======================================================================
collected 3 items
Test/test_mod1.py::test_01 FAILED [ 33%]
Test/test_mod1.py::test_02 FAILED [ 66%]
Test/test_mod1.py::test_03 FAILED [100%]
=========================================================================== FAILURES ===========================================================================
___________________________________________________________________________ test_01 ____________________________________________________________________________
def test_01():
> assert "a" == "b"
E AssertionError: assert 'a' == 'b'
E
E - b
E + a
Test\test_mod1.py:6: AssertionError
___________________________________________________________________________ test_02 ____________________________________________________________________________
def test_02():
> assert "a" == "b"
E AssertionError: assert 'a' == 'b'
E
E - b
E + a
Test\test_mod1.py:9: AssertionError
___________________________________________________________________________ test_03 ____________________________________________________________________________
def test_03():
> assert "a" == "b"
E AssertionError: assert 'a' == 'b'
E
E - b
E + a
Test\test_mod1.py:12: AssertionError
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_01 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_02 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_03 - AssertionError: assert 'a' == 'b'
====================================================================== 3 failed in 0.08s =======================================================================
- --tb=short:仅显示断言行和错误类型
===================================================================== test session starts ======================================================================
collected 3 items
Test/test_mod1.py::test_01 FAILED [ 33%]
Test/test_mod1.py::test_02 FAILED [ 66%]
Test/test_mod1.py::test_03 FAILED [100%]
=========================================================================== FAILURES ===========================================================================
___________________________________________________________________________ test_01 ____________________________________________________________________________
Test\test_mod1.py:6: in test_01
assert "a" == "b"
E AssertionError: assert 'a' == 'b'
E
E - b
E + a
___________________________________________________________________________ test_02 ____________________________________________________________________________
Test\test_mod1.py:9: in test_02
assert "a" == "b"
E AssertionError: assert 'a' == 'b'
E
E - b
E + a
___________________________________________________________________________ test_03 ____________________________________________________________________________
Test\test_mod1.py:12: in test_03
assert "a" == "b"
E AssertionError: assert 'a' == 'b'
E
E - b
E + a
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_01 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_02 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_03 - AssertionError: assert 'a' == 'b'
====================================================================== 3 failed in 0.07s =======================================================================
- --tb=line:单行输出错误文件、行号和错误摘要
===================================================================== test session starts ======================================================================
collected 3 items
Test/test_mod1.py::test_01 FAILED [ 33%]
Test/test_mod1.py::test_02 FAILED [ 66%]
Test/test_mod1.py::test_03 FAILED [100%]
=========================================================================== FAILURES ===========================================================================
D:\Projects\Python\PythonTest\Test\test_mod1.py:6: AssertionError: assert 'a' == 'b'
D:\Projects\Python\PythonTest\Test\test_mod1.py:9: AssertionError: assert 'a' == 'b'
D:\Projects\Python\PythonTest\Test\test_mod1.py:12: AssertionError: assert 'a' == 'b'
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_01 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_02 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_03 - AssertionError: assert 'a' == 'b'
====================================================================== 3 failed in 0.01s =======================================================================
- --tb=no:不显示 FAILURES 信息
===================================================================== test session starts ======================================================================
collected 3 items
Test/test_mod1.py::test_01 FAILED [ 33%]
Test/test_mod1.py::test_02 FAILED [ 66%]
Test/test_mod1.py::test_03 FAILED [100%]
=================================================================== short test summary info ====================================================================
FAILED Test/test_mod1.py::test_01 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_02 - AssertionError: assert 'a' == 'b'
FAILED Test/test_mod1.py::test_03 - AssertionError: assert 'a' == 'b'
====================================================================== 3 failed in 0.01s =======================================================================
初步构建测试套件
结合本章内容,我们可以初步构建一个测试套件。目录结构可以如下:
Project/
│
├── Package/ # 程序目录
│ ├── __init__.py # 包初始化文件,可以定义一些变量或执行一些操作。当然里面什么都不写也可以。
│ ├── module1.py # 测试程序模块,比如连接数据库操作数据,接口请求等操作,推荐按功能封装成类
│ └── module2.py # 测试程序模块,比如连接数据库操作数据,接口请求等操作,推荐按功能封装成类
│
├── Test/ # 测试用例目录
│ ├── __init__.py # 包初始化文件
│ ├── test_module1.py # 测试 module1 的测试用例
│ └── test_module2.py # 测试 module2 的测试用例
├── app.py # 项目启动文件
├── requirements.txt # 项目依赖项列表
└── README.md # 项目说明文档
一个完整的套件,需要有个启动文件 app.py ,测试时运行 app.py 文件。
app.py 文件可以这样设计:
from typing import Union
import pytest
import sys
import logging
import argparse
import os
# 自定义日志格式
LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s'
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
logger = logging.getLogger(__name__)
def run_tests(test_target: str, testprint: str, tb: str)->int:
"""
运行pytest测试并返回退出码
Args:
test_target (str): 测试目标路径
testprint (str): 控制输出信息的命令行参数
tb (str): 控制输出信息的命令行参数
Returns:
int: pytest退出码
"""
if not os.path.exists(test_target):
logger.error(f"测试目标路径不存在: {test_target}")
return 1
# 构建pytest参数
pytest_args = []
if testprint:
pytest_args.append("-"+ testprint)
pytest_args.extend([
test_target,
"--tb=" + tb
])
try:
logger.info(f"开始运行测试,目标路径: {test_target}")
exit_code = pytest.main(pytest_args)
# 退出码说明映射
exit_messages = {
0: "✅ 全部测试用例通过",
1: "⚠️ 部分测试用例未通过",
2: "❌ 测试过程中有中断或其他非正常终止",
3: "❌ 内部错误",
4: "❌ pytest无法找到任何测试用例",
5: "❌ pytest遇到了命令行解析错误"
}
logger.info(exit_messages.get(exit_code, f"❓ 未知的退出码: {exit_code}"))
return exit_code
except Exception as e:
logger.exception("运行测试时发生致命错误:")
logger.debug("异常详情:", exc_info=True)
return 1
def parse_arguments()-> argparse.Namespace:
"""解析命令行参数"""
parser = argparse.ArgumentParser(description="使用指定的命令运行 pytest 测试")
parser.add_argument(
'test_target',
nargs='?',
type=str,
default="Test/",
help='指定测试目录文件 (默认: Test/)'
)
parser.add_argument(
'-p', '--testprint',
nargs='?',
type=str,
default="",
choices=["","v", "ra", "rA", "rp", "rx", "rs", "rN", "vra", "vrA", "vrp", "vrx", "vrs", "vrN"],
help='控制输出信息'
)
parser.add_argument(
'-tb', '--tb',
nargs='?',
type=str,
default="auto",
choices=["auto","long", "short", "line", "native", "no"],
help='控制输出信息'
)
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
exit_code = run_tests(args.test_target, args.testprint, args.tb)
sys.exit(exit_code)
项目根目录下,可以这样运行指定测试用例:
- 运行 Test/ 目录下的所有测试用例:
python app.py
- 后面加文件路径,运行特定文件,如:
python app.py Test/test_module1.py
- 后面加测试用例路径,运行特定模块文件中的特定测试用例,如:
python app.py Test/test_module1.py::test_case
- 后面加测试组路径,运行特定文件中的特定测试组,如:
python app.py Test/test_module1.py::TestClass
- 后面加测试用例路径,运行特定文件中的特定测试组中的特定测试用例,如:
python app.py Test/test_module1.py::TestClass::test_case
- 后面再加参数,控制输出信息,如:
python app.py Test/test_module1.py -p vra -tb no
python app.py Test/test_module1.py -p rs
绵薄之力
最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走
软件测试面试资料
被百万人刷爆的软件测试题库!!!谁用谁知道!!!卷起来!
这些资料,对于想进阶【自动化测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。希望对大家有所帮助…….