如何使用 Pytest 管理测试用例
编写测试用例
在 toffee 中,测试用例是通过 pytest 来管理的。pytest 是一个功能强大的 Python 测试框架,如果你不熟悉 pytest,可以查看 pytest 官方文档。
编写第一个测试用例
首先,我们需要创建一个测试用例文件,例如 test_adder.py,该文件需要以 test_ 开头,或以 _test.py 结尾,以便 pytest 能够识别。接着可以在其中编写我们的第一个测试用例。
# test_adder.py
async def my_test():
env = AdderEnv()
env.add_agent.exec_add(1, 2, 0)
def test_adder():
toffee.run(my_test())
pytest 并不能直接运行协程测试用例,因此我们需要在测试用例中调用 toffee.run 来运行异步测试用例。
用例编写完成后,我们可以在终端中运行 pytest。
pytest
pytest 会查找当前目录下所有以 test_ 开头或以 _test.py 结尾的文件,并运行其中以 test_ 开头的函数,每一个函数被视作一个测试用例。
运行协程测试用例
为了使 pytest 能够直接运行协程测试用例,toffee 提供了 toffee_async 标记来标记异步测试用例。
# test_adder.py
@pytest.mark.toffee_async
async def test_adder():
env = AdderEnv(DUTAdder())
await env.add_agent.exec_add(1, 2, 0)
如图所示,我们只需要在测试用例函数上添加 @pytest.mark.toffee_async 标记,pytest 就能够直接运行协程测试用例。
生成测试报告
在运行 pytest 时,toffee 会自动收集测试用例的执行结果,自动统计覆盖率信息,并生成一个验证报告,想要生成该报告,需要在调用 pytest 时添加 --toffee-report 参数。
pytest --toffee-report
默认情况下,toffee 将会为每次运行生成一个默认报告名称,并将报告放至 reports 目录下。可以通过 --report-dir 参数来指定报告的存放目录,通过 --report-name 参数来指定报告的名称。
但此时,由于 toffee 无法得知覆盖率文件名称,因此在报告中无法显示覆盖率信息,如果想要在报告中显示覆盖率信息,需要在每个测试用例中传入功能覆盖组及行覆盖率文件的名称。
@pytest.mark.toffee_async
async def test_adder(request):
adder = DUTAdder(
waveform_filename="adder.fst",
coverage_filename="adder.dat"
)
g = CovGroup("Adder")
env = AdderEnv(adder)
await env.add_agent.exec_add(1, 2, 0)
adder.Finish()
set_func_coverage(request, cov_groups)
set_line_coverage(request, "adder.dat")
上述代码中,在创建 DUT 时,我们传入了波形文件和覆盖率文件的名称,使得 DUT 在运行时可以生成指定名称的覆盖率文件。接着我们定义了一个覆盖组,来收集 DUT 的功能覆盖率信息,具体如何使用将在下个文档中介绍。
接着,调用了 DUT 的 Finish 方法,用于结束波形文件的记录。最终我们通过 set_func_coverage 和 set_line_coverage 函数来设置功能覆盖组及行覆盖率文件信息。
此时再次运行 pytest 时,toffee 将会自动收集覆盖率信息,并在报告中显示。
使用 toffee-test 管理资源
然而,上述过程过于繁琐,并且为了保证每个测试用例之间文件名称不产生冲突,我们需要在每个测试用例中传入不一样的文件名称。并且在测试用例出现异常时,测试用例并不会运行完毕,导致覆盖率文件无法生成。
因此,toffee-test 提供了 toffee_request Fixture 来管理资源,简化了测试用例的编写。
# test_adder.py
@pytest.mark.toffee_async
async def test_adder(my_request):
dut = my_request
env = AdderEnv(dut)
await env.add_agent.exec_add(1, 2, 0)
@pytest.fixture()
def my_request(toffee_request: ToffeeRequest):
toffee_request.add_cov_groups(CovGroup("Adder"))
return toffee_request.create_dut(DUTAdder)
Fixture 是 pytest 中的概念,例如上述代码中定义了一个名为 my_request 的 Fixture。如果在其他测试用例的输出参数中含有 my_request 参数,pytest 将会自动调用 my_request Fixture,并将其返回值传入测试用例。
上述代码中自定义了一个 Fixture my_request,并在测试用例中进行使用,这也就意味着资源的管理工作都将会在 Fixture 中完成,测试用例只需要关注测试逻辑即可。my_request 必须使用 toffee-test 提供的 toffee_request Fixture 作为参数,以便进行资源管理,toffee_request 提供了一系列的方法来管理资源。
通过 add_cov_groups 添加覆盖组,toffee-test 会自动将其生成至报告中。
通过 create_dut 创建 DUT 实例,toffee-test 会自动管理 DUT 的波形文件和覆盖率文件的生成,并确保文件名称不产生冲突。
在 my_request 中,可以自定义返回值传入测试用例中。如果想要任意测试用例都可以访问到该 Fixture,可以将 Fixture 定义在 conftest.py 文件中。
至此,我们实现了测试用例资源管理和逻辑编写的分离,无需在每个测试用例中手动管理资源的创建与释放。