fixture参数化精简测试代码
一、前言
Pytest测试框架中的fixture,可以将自动化测试用例中的前置、后置部分分离出来放入其中,然后在写测试用例的时候只需要写测试逻辑相关的代码,提高代码的复用性,同时也有利于代码的维护。
本文重点介绍的是fixture参数化,关于fixture的基础知识可以查看这个链接:https://www.cnblogs.com/zdx20/p/14948134.html
二、测试场景介绍
我们以下面App自动化测试,订酒店的测试场景为例,来说明:
上图中有三个测试场景:
1、编辑姓名;
2、编辑手机号;
3、编辑身份证。
这三个场景主要的测试逻辑都在酒店的编辑订单页,通过fixture参数化功能可以很好的精简测试代码。
三、fixture和fixture参数化
1、按照上面的流程编写自动化测试用例:
import pytest
login_data = [{"user_name": "xiaowang", "pwd": 123456, "date": 1, "name": "小王"}]
@pytest.mark.parametrize("test_data", login_data)
def test_hotel(test_data):
# 登录App
print("\n" + "1、登录App, 账号和密码是:", test_data["user_name"], test_data["pwd"])
# 酒店首页选择入住日期
print("2、酒店首页选择日期:{}号".format(test_data["date"]))
# 酒店列表选择酒店
print("3、选择想要预订的酒店和房型")
# 编辑酒店页面,输入入住人姓名
print("4、输入入住人姓名:", test_data["name"])
# 断言下单结果
print("5、恭喜,酒店预订成功了!!!")
上面的用例就是没有使用前置/后置分离代码,虽然可以完成UI自动化测试的一个测试场景任务,但是后续用例多了维护会非常头疼,而且不具有扩展性。
2、fixture的前置、后置
在每条用例中都需要登录App,然后执行测试过程,最后断言测试结果。我们可以将登录,和测试结果断言剥离出来放在fixture当中,这样同类型的测试场景就可以直接调用。
import pytest
hotel_data = [{"date": 1, "name": "小王"}]
@pytest.fixture()
def fix_login():
# 登录App
print("\n" + "1、前置条件--登录App, 账号和密码是:", "xiaowang", 123456)
yield
# 断言下单结果
print("5、后置条件--恭喜,酒店预订成功了!!!")
@pytest.mark.parametrize("test_data", hotel_data) # 测试数据的参数化
def test_hotel(test_data, fix_login):
# 酒店首页选择入住日期
print("2、酒店首页选择日期:{}号".format(test_data["date"]))
# 酒店列表选择酒店
print("3、选择想要预订的酒店和房型")
# 编辑酒店页面,输入入住人姓名
print("4、输入入住人姓名:", test_data["name"])
执行结果如下:
1、前置条件--登录App, 账号和密码是: xiaowang 123456
2、酒店首页选择日期:1号
3、选择想要预订的酒店和房型
4、输入入住人姓名: 小王
5、后置条件--恭喜,酒店预订成功了!!!
上面的测试用例方法中,测试数据是通过@pytest.mark.parametrize()传入的,有几组测试数据就会生成几条测试用例,详细的使用方法可以查看“前言”部分提到的链接。
3、fixture参数化
通过fixture我们将用例的前置和后置条件摘出来了,但是前置条件登录的数据是固定的,通用性不强,需要将fixture的测试数据也参数化。
fixture参数化传参的方法与用例的传参是一样的,也是使用@pytest.mark.parametrize()传入,但是需要加一个参数:indirect=True,指定将参数传入fixture测试夹具中。fixture测试夹具的方法中使用request接受传入的参数,然后通过request.param使用具体的数据。
import pytest
login_data = [{"user_name": "xiaowang", "pwd": 1234}, {"user_name": "zhaosi", "pwd": 6789}]
test_data = [{"date": 1, "name": "小王"}]
@pytest.fixture()
def fix_login(request):
# 接收传入的数据
test_info = request.param
# 登录App
print("\n" + "1、前置条件--登录App, 账号和密码是:", test_info["user_name"], test_info["pwd"])
yield
# 断言下单结果
print("5、后置条件--恭喜,酒店预订成功了!!!")
@pytest.mark.parametrize("fix_login", login_data, indirect=True) # fixture测试夹具的参数化
@pytest.mark.parametrize("test_info", test_data) # 测试用例的参数化
def test_hotel(test_info, fix_login):
# 酒店首页选择入住日期
print("2、酒店首页选择日期:{}号".format(test_info["date"]))
# 酒店列表选择酒店
print("3、选择想要预订的酒店和房型")
# 编辑酒店页面,输入入住人姓名
print("4、输入入住人姓名:", test_info["name"])
上面登录的前置条件中,传入了两组账号、密码数据,那么在执行用例时,同一个用例场景会分别使用两个账号测试一遍。
同时等到两个执行结果:
fixture参数化,需要注意接收参数的标识符,用例中调用测试夹具的标识符,以及测试夹具的方法名要一致。
现在测试场景只写了一个:编辑姓名,后面的编辑手机号、编辑身份证号两个场景,直接套用现有的测试用例即可。
4、拆分多个fixture
前面提到我们需要测试的三个酒店场景,前面几个步骤“酒店首页”、“酒店列表页”都是一样的,而且后续还有其他用例也需要用到“酒店首页”或者“酒店列表页”,因此我们需要不同页面的前置条件来满足不同测试场景,这就有了很多个测试夹具,不利于代码的维护。我们可以按照一个页面一个前置夹具的方法来细分测试场景,写用例时按照顺序去调用即可。
import pytest
login_data = [{"user_name": "xiaowang", "pwd": 1234}]
test_data = [{"date": 11, "name": "小王", "result_data": "通过"}]
@pytest.fixture()
def fix_login(request):
# 接收传入的数据
test_info = request.param
# 登录App
print("\n" + "1、前置条件--登录App, 账号和密码是:", test_info["user_name"], test_info["pwd"])
@pytest.fixture()
def home_page(request):
# 接收传入的数据
test_info = request.param
# 酒店首页选择入住日期
print("2、酒店首页选择日期:{}号".format(test_info["date"]))
@pytest.fixture()
def list_page():
# 酒店列表选择酒店
print("3、选择想要预订的酒店和房型")
@pytest.fixture()
def result(request):
yield
# 接收传入的数据
test_info = request.param
# 断言下单结果
print("5、后置条件--恭喜,酒店预订成功了,结果:{}!!!".format(test_info["result_data"]))
@pytest.mark.parametrize("result", test_data, indirect=True)
@pytest.mark.parametrize("home_page", test_data, indirect=True)
@pytest.mark.parametrize("fix_login", login_data, indirect=True)
@pytest.mark.parametrize("test_info", test_data)
def test_name(test_info, fix_login, home_page, list_page, result):
# 编辑酒店页面,输入入住人姓名
print("4、输入入住人姓名:", test_info["name"])
执行结果如下:
1、前置条件--登录App, 账号和密码是: xiaowang 1234
2、酒店首页选择日期:11号
3、选择想要预订的酒店和房型
4、输入入住人姓名: 小王
5、后置条件--恭喜,酒店预订成功了,结果:通过!!!
###注意:在测试用例方法中同时调用多个fixture夹具时,一定要按照测试逻辑顺序来,执行用例时会按照测试夹具调用先后顺序执行。
4.1、fixture测试夹具添加顺序
测试用例方法中调用测试夹具时需要注意先后顺序,不然测试逻辑会混乱。如果你不想在调用时出现这个问题,可以在编写多个测试夹具时,测试夹具之间按照逻辑先后顺序调用,这样在写用例时就不用考虑先后顺序问题,而且不需要传参的测试夹具不用调用也能执行。
测试用例方法调用:
四、使用params参数
1、fixture的params参数
fixture测试夹具的参数化除了上面用到的@pytest.mark.parametrize(),还有一种是直接在测试夹具的fixture中传参,使用params=即可。
import pytest
login_data = [{"user_name": "xiaowang", "pwd": 1234}, {"user_name": "zhaosi", "pwd": 6789}]
test_data = [{"date": 1, "name": "小王"}]
@pytest.fixture(params=login_data) # fixture测试夹具的参数化
def fix_login(request):
# 接收传入的数据
test_info = request.param
# 登录App
print("\n" + "1、前置条件--登录App, 账号和密码是:", test_info["user_name"], test_info["pwd"])
yield
# 断言下单结果
print("5、后置条件--恭喜,酒店预订成功了!!!")
@pytest.mark.parametrize("test_info", test_data) # 测试用例的参数化
def test_hotel(test_info, fix_login):
# 酒店首页选择入住日期
print("2、酒店首页选择日期:{}号".format(test_info["date"]))
# 酒店列表选择酒店
print("3、选择想要预订的酒店和房型")
# 编辑酒店页面,输入入住人姓名
print("4、输入入住人姓名:", test_info["name"])
fixture的参数化就介绍到这里。