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.pylist_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 FalseTest\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.pyclass TestCaseGroup:@staticmethoddef test_case1():x = "this"assert "h" in x, "字符串中没有 h"@staticmethoddef test_case2():x = 1y = 2assert 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 ___________________________________________________________________ @staticmethoddef test_case2():x = 1y = 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.pydef test_case1():x = "this"assert "h" in x, "字符串中没有 h"def test_case2():x = 1y = 2assert 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 = 1y = 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 = 1y = 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 pytestdef test_pass():x = "this"assert "h" in x, "字符串中没有 h"def test_fail():x = 1y = 2assert 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 = 1y = 2assert type(x) != type(y), "x 不等于 y"@pytest.mark.skip(reason="skip")
def test_skip():x = 1y = 2assert 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 = 1y = 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 = 1y = 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 = 1y = 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 = 1y = 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 = 1y = 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 = 1y = 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 = 1y = 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         + aTest\test_mod1.py:6: AssertionError
___________________________________________________________________________ test_02 ____________________________________________________________________________ def test_02():
>       assert "a" == "b"
E       AssertionError: assert 'a' == 'b'
E
E         - b
E         + aTest\test_mod1.py:9: AssertionError
___________________________________________________________________________ test_03 ____________________________________________________________________________ def test_03():
>       assert "a" == "b"
E       AssertionError: assert 'a' == 'b'
E
E         - b
E         + aTest\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_01assert "a" == "b"
E   AssertionError: assert 'a' == 'b'
E     
E     - b
E     + a
___________________________________________________________________________ test_02 ____________________________________________________________________________ 
Test\test_mod1.py:9: in test_02assert "a" == "b"
E   AssertionError: assert 'a' == 'b'
E     
E     - b
E     + a
___________________________________________________________________________ test_03 ____________________________________________________________________________ 
Test\test_mod1.py:12: in test_03assert "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 Unionimport 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_codeexcept Exception as e:logger.exception("运行测试时发生致命错误:")logger.debug("异常详情:", exc_info=True)return 1def 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

绵薄之力

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走


软件测试面试资料

被百万人刷爆的软件测试题库!!!谁用谁知道!!!卷起来!

​这些资料,对于想进阶【自动化测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。希望对大家有所帮助…….

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/91130.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/91130.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/91130.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nacos docker 配置

docker.io/nacos 项目中国可用镜像列表 | 高速可靠的 Docker 镜像资源 1、Docker 拉取镜像 docker pull nacos/nacos-server:v2.1.0 2、创建宿主机挂载目录 mkdir -p /mydata/nacos/logs/ mkdir -p /mydata/nacos/conf/ AI写代码 3、启动nacos并复制文件到宿主机&#xff0…

Django 模板(Template)

1. 模板简介 作为 Web 开发框架,Django 提供了模板,可以很便利的动态生成 HTML。模版系统致力于表达外观,而不是程序逻辑。 模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用。 模板包含: HTM…

Word 文字编辑状态下按回车换行后是非正文格式

在Word里编辑时&#xff0c;按回车后新段落突然变成标题1、标题2这类格式&#xff0c;不再是正文样式&#xff0c;这通常是因为「正文」的样式设置出了问题——可能被默认设置成“后续段落自动应用标题1/标题2格式”了。 修改方法很简单&#xff1a; 找到并打开「正文」样式的修…

PySide6 UI 灵活性:QToolBar 的浮动与停靠及 QSplitter 的可调整面板

PySide6 UI 灵活性&#xff1a;QToolBar 的浮动与停靠及 QSplitter 的可调整面板 在现代桌面应用程序开发中&#xff0c;提供灵活且用户友好的界面至关重要。PySide6&#xff08;Qt for Python&#xff09;提供了强大的工具来构建这样的界面。本文将深入探讨两个关键的 PySide6…

B4016 树的直径

B4016 树的直径 - 洛谷 题目描述 给定一棵 n 个结点的树&#xff0c;树没有边权。请求出树的直径是多少&#xff0c;即树上最长的不重复经过一个点的路径长度是多少。 输入格式 第一行输入一个正整数 n&#xff0c;表示结点个数。 第二行开始&#xff0c;往下一共 n - 1 行…

【一维 前缀和+差分】

一、一维前缀和 1.1 定义 给定一个数组 a[1..n]&#xff0c;其前缀和数组 pre[1..n] 定义为&#xff1a; pre[i]a[1]a[2]⋯a[i] pre[i] a[1] a[2] \dots a[i] pre[i]a[1]a[2]⋯a[i] 即 pre[i] 表示原数组从第 1 项到第 i 项的和。 1.2 构建 int a[N], pre[N]; for (int i …

Spring Boot 双数据源配置

文章目录什么是双数据源&#xff1f;为什么需要双数据源&#xff1f;核心实现原理完整示例注意什么是双数据源&#xff1f; 双数据源是指在一个应用程序中同时配置和使用两个不同的数据库连接。比如&#xff1a; 一个连接订单数据库&#xff0c;处理业务数据一个连接用户中心…

【Java】【力扣】102.二叉树层序遍历

思路一个辅助队列&#xff08;初始化队列&#xff1a;根节点入队&#xff09;一个节点 出队&#xff0c;他的左右孩子入队循环 直到队列为空举例代码public List<List<Integer>> levelOrder(TreeNode root) {if (rootnull){return new ArrayList<List<Intege…

为什么有些PDF无法复制文字?原理分析与解决方案

在日常办公和学习中&#xff0c;我们经常会从PDF文件中复制文字&#xff0c;用于编辑、引用、整理笔记。但你是否也遇到过这样的情况&#xff1a;有些PDF中的文字根本无法选中&#xff0c;更无法复制粘贴&#xff1f; 看起来像是“文字”&#xff0c;但操作上却完全无效——这…

LabVIEW浏览器ActiveX事件交互

​程序围绕 WebBrowser ActiveX 控件&#xff0c;借 “Reg Event Callback” 注册标题变更回调&#xff0c;“Callback - Title Change.vi” 处理标题数据&#xff0c;“Monitor...” 响应 URL 变更&#xff0c;“Unregister...” 清理资源&#xff0c;实现浏览器事件交互与管控…

C++后端面试八股文

一、C 语言基础与底层原理请解释 new / delete 和 malloc / free 的区别和联系&#xff0c;以及使用它们时需要注意什么new 和 delete 是C的​​运算符&#xff08;Operator&#xff09;​​。这意味着它们可以被类&#xff08;通过 operator new 和 operator delete&#xff0…

基础分类模型及回归简介(一)

一、先搞懂两个核心任务&#xff1a;分类和回归咱们生活中总遇到要 “判断” 或 “预测” 的事&#xff1a;比如看到一个水果&#xff0c;判断是苹果还是橘子 —— 这就是分类&#xff08;结果是 “类别”&#xff09;&#xff1b;比如根据西瓜的大小、颜色&#xff0c;猜它能卖…

【LeetCode 热题 100】114. 二叉树展开为链表——(解法二)分治

Problem: 114. 二叉树展开为链表 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序…

【WPF】WPF 自定义控件 实战详解,含命令实现

&#x1f9e9;《WPF 自定义控件》实战详解本文将围绕如何编写一个自定义控件&#xff08;如带右键菜单的图片控件 ImageView&#xff09;&#xff0c;逐步讲解其定义、命令绑定与 ContextMenu 中常见的语法技巧。&#x1f9f1; 一、创建一个 WPF 自定义控件的步骤 WPF 中自定义…

Flink 2.0 DataStream算子全景

在实时流处理中&#xff0c;Apache Flink的DataStream API算子是构建流处理 pipeline 的基础单元。本文基于Flink 2.0&#xff0c;聚焦算子的核心概念、分类及高级特性。 一、算子核心概念&#xff1a;流处理的"原子操作 1. 数据流拓扑&#xff08;Stream Topology&#x…

Flask 入门到实战(2):使用 SQLAlchemy 打造可持久化的数据层

Flask 入门到实战&#xff1a;使用 SQLAlchemy 打造可持久化的数据层一、前言&#xff1a;为什么用 Flask-SQLAlchemy&#xff1f; 在 Python Web 开发中&#xff0c;操作数据库的方式主要有两种&#xff1a; 直接写 SQL&#xff08;繁琐且难维护&#xff09;使用 ORM&#xff…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | GithubProfies(GitHub 个人资料)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— GithubProfies组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script setup…

simscape中坐标系和坐标变换Frames and Transforms

为了更便捷地描述单个物体的运动&#xff0c;最好以该物体的质心为坐标原点建立坐标系&#xff0c;从而可以非常方便地描述其旋转运动。因此&#xff0c;在计算多个物体之间的位置关系时&#xff0c;为了计算方便&#xff0c;需要频繁地更换坐标框架&#xff0c;这也是multibod…

构建分布式光伏“四可”能力:支撑新型电力系统安全稳定运行的关键路径

随着我国新能源装机规模的跨越式增长&#xff0c;国家能源战略对新能源电站的规范化接入与精细化调度管理提出了更高要求。在电力市场化改革深化与新型电力系统构建的关键时期&#xff0c;保障电网安全稳定、提升新能源高效消纳能力已成为核心议题。国家能源局于2025年1月17日正…

UART寄存器介绍

在 STM32 微控制器中&#xff0c;UART&#xff08;通用异步收发传输器&#xff09;通信通过多个寄存器实现配置和数据传输。下面详细解析 UART 的核心寄存器及其功能。1. 状态寄存器&#xff08;USART_SR&#xff09;状态寄存器反映 UART 当前的工作状态&#xff0c;用于判断数…