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("
" + "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("
" + "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("
" + "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("
" + "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("
" + "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的参数化就介绍到这里。

原文地址:https://www.cnblogs.com/zdx20/p/15203408.html