Py.test-将变量从csv应用到decorator



请耐心等待,当我试图解释我的困境时,我仍然是Python新手,所以我的术语可能不正确。此外,我对这篇文章不可避免的冗长感到抱歉,但我会尽可能多地阐述相关细节。

简要介绍:

我目前正在为一组功能基本相同的网站开发一套Selenium测试,使用py.test

  • 使用pytest插件pytest TestRail将测试结果上传到TestRail。

  • 测试用decorator@pytestrail.case(id(标记,并带有唯一的用例id

我的一个典型测试如下:

@pytestrail.case('C100123')  # associates the function with the relevant TR case
@pytest.mark.usefixtures()
def test_login():
# test code goes here

正如我之前提到的,我的目标是创建一组代码来处理我们的许多网站,这些网站具有(几乎(相同的功能,所以上面例子中的硬编码装饰器不起作用。

我尝试了一种数据驱动的方法,在TestRail中使用csv和测试及其用例ID的列表。

示例:

website1.csv:
Case ID | Test name
C100123 | test_login

website2.csv:
Case ID | Test name
C222123 | test_login

我编写的代码将使用inspect模块来查找正在运行的测试的名称,找到相关的测试ID,并将其放入一个名为test_ID:的变量中

import csv
import inspect
class trp(object):
def __init__(self):
pass

with open(testcsv) as f:  # testcsv could be website1.csv or website2.csv
reader = csv.reader(f)
next(reader)  # skip header
tests = [r for r in reader]

def gettestcase(self):
self.current_test = inspect.stack()[3][3]
for row in trp.tests:
if self.current_test == row[2]:
self.test_id = (row[0])
print(self.test_id)
return self.test_id, self.current_test

def gettestid(self):
self.gettestcase()

当时的想法是,装饰器将根据我当时使用的csv进行动态更改。

@pytestrail.case(test_id)  # now a variable
@pytest.mark.usefixtures()
def test_login():
trp.gettestid()
# test code goes here

因此,如果我为website1运行test_login,装饰器将看起来像:

@pytestrail.case('C100123')

如果我为website2运行test_login,装饰器将是:

@pytestrail.case('C222123')

我为自己想出这个解决方案感到非常自豪,并尝试了一下。。。它不起作用。虽然代码本身可以工作,但我会得到一个异常,因为test_id是未定义的(我理解为什么在decorator之后执行-gettestcase,所以它当然会崩溃

我能处理这个问题的唯一其他方法是在执行任何测试代码之前应用csv和testIDs。我的问题是——我怎么知道如何将测试与其测试ID相关联?一个优雅的、最小的解决方案是什么?

很抱歉问了这么长的问题。如果你需要更多的解释,我会密切关注,回答任何问题。

pytest非常擅长为测试做各种元编程。如果我正确理解你的问题,下面的代码将使用pytestrail.case标记进行动态测试标记。在项目根目录中,创建一个名为conftest.py的文件,并在其中放置以下代码:

import csv
from pytest_testrail.plugin import pytestrail

with open('website1.csv') as f:
reader = csv.reader(f)
next(reader)
tests = [r for r in reader]

def pytest_collection_modifyitems(items):
for item in items:
for testid, testname in tests:
if item.name == testname:
item.add_marker(pytestrail.case(testid))

现在,您根本不需要用@pytestrail.case()标记测试——只需编写其余代码,pytest将负责标记:

def test_login():
assert True

pytest启动时,上面的代码将读取website1.csv并存储测试ID和名称,就像您在代码中所做的那样。在测试运行开始之前,pytest_collection_modifyitems钩子将执行,分析收集的测试-如果测试与csv文件中的名称相同,pytest将向其添加带有测试ID的pytestrail.case标记。

我相信这没有像你预期的那样起作用的原因与python读取和执行文件的方式有关。当python开始执行时,它读取链接的python文件,并依次逐个执行每一行。对于"根"缩进级别的东西(函数/类定义、装饰器、变量赋值等(,这意味着它们在加载时只运行一次,再也不会运行了。在您的案例中,python解释器读取pytest testrail装饰器,然后读取pytest装饰器,最后读取函数定义,每次执行一次。

(附带说明,这就是为什么永远不应该使用可变对象作为函数参数默认值:Common Gotchas(

假设您想首先推导出当前的测试名称,然后将其与测试用例ID相关联,最后将该ID与decorator一起使用,我不确定这在pytest-testrail的当前功能中是否可行。至少,如果没有一些深奥且难以使用描述符等进行调试/维护的破解,这是不可能的。

我认为您实际上有一个选择:使用不同的TestRail客户端,并更新您的pytest结构以使用新客户端。我可以推荐的两个python客户端是testrail python和TRAW(testrail Api Wrapper((*(

您将需要更多的工作来创建用于开始运行、更新结果和结束运行的固定装置,但我认为最终您将拥有一套更可移植的测试和更好的结果报告。

(*(全面披露:我是TRAW的创建者/维护者,也为testrail-python做出了重大贡献

相关内容

  • 没有找到相关文章

最新更新