接口自动化测试:Python+Pytest+Requests+Allure

本项目实现了对Daily Cost的接口测试:

  • Python+Requests 发送和处理HTTP协议的请求接口
  • Pytest 作为测试执行器
  • YAML 管理测试数据
  • Allure 来生成测试报告。

本项目是参考了pytestDemo做了自己的实现。

1. 项目结构及安装部署

项目结构

  • api: 接口封装层,如封装HTTP接口为Python接口
  • commom: 从文件中读取数据等各种工具类
  • core: requests 请求方法封装、关键字返回结果类
  • config: 环境、数据库连接等配置
  • data: 测试数据文件管理
  • operation: 关键字封装层,如把多个Python接口封装为关键字
  • pytest.ini: pytest 配置文件
  • requirements.txt: 相关依赖包文件
  • testcases: 测试用例
  • api_test: 单接口测试
  • scenario_test: 场景/业务流程测试

安装部署

  • 部署Daily Cost应用:教程
  • 下载本测试项目源代码 ,通过pip安装相应依赖pip3 install -r requirements.txt,根据实际情况修改setting.ini中的相应内容
  • 输入pytest运行测试
  • 如果想要使用Allure查看生成的测试报告,需要先安装Allure服务:brew install allure

2. 环境配置

  • 在config-setting.ini文件中定义api_root_url
  • 在common-read_data.py中实现load_ini()方法读取配置文件
  • 在需要使用api_root_url的地方调用load_ini(data_file_path),读取对应的value

3. 封装HTTP请求

  1. 封装requests请求方法:将requests中发送GET、POST、PUT、DELETE等方法封装到RestClient类中
  2. 定义被测API接口Request:在api文件夹中根据domain创建对应请求的集合类,如class User(RestClient),并定义各接口信息,如登录接口:
def login(self, **kwargs):         
    return self.post("/login", **kwargs)

4. 关键字封装

关键字应当是具有一定业务意义的。在封装关键字的时候,可以只封装一个接口,也可以调用多个接口来完成。

比如我们要测试记一笔,在接口调用成功后接口只会返回账单的ID,还需要调用查询账单明细接口,来帮助判断每个字段是否与输入时的一致,那么我们可以这样来进行测试:

  • 首先,将记一笔-查看明细的操作封装为一个关键字,在这个关键字中依次调用记一笔和查询账单明细结果,并可以自定义关键字的返回结果
  • 接着,在编写测试用例的时候,直接调用关键字来进行测试,这时就可以关键字的返回结果,断言的时候,也可以直接对关键字返回结果进行断言

再比如查询月度账单统计结果,一个接口就可以独立完成业务查询操作,我们在关键字中只调用这一个接口即可。

回到本项目,具体的代码逻辑如下:

  1. 在operation文件夹中,还是按照domain分文件来组织各关键字
  2. 在core中定义关键字返回的数据结构类 ResultBase
  3. 定义关键字,在调用对应API请求时需要明确传递接口请求参数,并定义返回结果
def bill_monthly_stat(date, token):
   header = {
       "Content-Type": "application/json",
       "Authorization": "Bearer " + token
   }
   param = {"date": date}
   res = bill_details.get_bill_monthly(params=param, headers=header)

   return ResultBase(res)

本项目中的关键字中都只封装了一个请求。

5. 单接口测试

记一笔接口为例。

  • 定义接口及关键字
// api -> bill.py : 定义接口
def create_new_bill(self, **kwargs):
    return self.post("/bill", **kwargs)

// operation -> bill.py : 定义关键字
def bill_create(category_id, type, amount, note, date, token):
    payload = {
        "categoryId": category_id,
        "type": type,
        "amount": amount,
        "note": note,
        "date": date
    }
    header = {
        "Content-Type": "application/json",
        "Authorization": "Bearer " + token
    }
    res = bill.create_new_bill(json=payload, headers=header)

    return ResultBase(res)
  • 接口测试类
// testcases -> api_test -> bill -> test_bill_create.py
class TestBillCreate():
    @mark.smoke
    @mark.parametrize('category_id, type, amount, note, date, status_code, message', 
                    [
        ("5442d3b8-9d4a-4654-bf0b-d2249efef190", "EXPENSE", 100.01, "note1111test", "2021-12-01", 200, "操作成功"),
        ("66c22fad-be9d-481d-a445-c57d266bf938", "INCOME", 1000.01, "note1111test", "2021-12-01", 200, "操作成功")
        ])
    def test_bill_create_success(self, category_id, type, amount, note, date, status_code, message, token):
        result = bill_create(category_id, type, amount, note, date, token)
        assert result.response.status_code == status_code
        assert result.message == message
        assert result.response.json()["data"]["id"]
  • @mark.smoke是使用了pytest的mark标记功能,运行时使用命令pytest -m smoke只运行标记为smoke的用例
  • @mark.parametrize是pytest的变量参数化功能,可以实现数据驱动测试,如上所示有两条参数化数据,则该用例会应用这两条数据共执行两次
  • 调用bill_create时有一个token参数,它实际上是在conftest.py文件中定义的
  • pytest中的assert使用的是python内置的断言库

6. YAML文件管理测试数据

在上面的例子中我们在使用@mark.parametrize时直接将具体的测试数据写在了用例上方。为了后期修改维护效率更高,我们通常会将测试数据和用例分离,即可以采用yaml文件来单独管理测试数据,conftest.py可以帮助数据的读取。

  • 定义yaml文件:data -> api_test_data.yml
test_bill_create_success:
  # category_id, type, amount, note, date, status_code, message
  - ["5442d3b8-9d4a-4654-bf0b-d2249efef190", "EXPENSE", 100.01, "note1111test", "2021-12-01", 200, "操作成功"]
  - ["66c22fad-be9d-481d-a445-c57d266bf938", "INCOME", 1000.01, "note1111test", "2021-12-01", 200, "操作成功"]
  • key为测试用例对应的函数名test_bill_create_success
  • -表示value是数组
  • conftest.py中读取对应的测试数据
import pytest
import os
from common.read_data import data 

BASE_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
def get_data(yaml_file_name):
    try:
        data_file_path = os.path.join(BASE_PATH, "data", yaml_file_name)
        yaml_data = data.load_yaml(data_file_path)
    except Exception as ex:
        pytest.skip(str(ex))
    else:
        return yaml_data

api_data = get_data("api_test_data.yml")
  • 参数化时从yaml文件中读取数据
@mark.parametrize('category_id, type, amount, note, date, status_code, message', 
                    api_data["test_bill_create_success"])

7. API场景测试

在做API测试时,除了单个接口输入输出的校验,由多个接口串联成的业务场景的测试也是必不可少的。

简单的,我们以登录后进入首页为例,接口调用为:登录 -> 查询当月账单明细列表 -> 查询当月账单统计值。

  • 定义场景测试类
// testcases -> scenario_test -> test_get_one_month_bill.py
import allure
import pytest
from operation.user import login_user
from operation.bill import one_month_bill_list_get_by_date, bill_monthly_stat

@pytest.mark.core
class TestGetOneMonthBill:

    @allure.title("01: user[yuxiaomeng] login")
    @allure.story('story_1')
    def test_user_login(self, core_env):
        result = login_user('yuxiaomeng', '20211030.y')
        assert result.status_code == 200
        assert result.data["token"]
        core_env["token"] = result.data["token"]

    @allure.title("02: get homepage info - bill details list")
    @allure.story('story_1')
    def test_get_current_month_monthly_bill_list(self, core_env):
        result = one_month_bill_list_get_by_date(core_env["date"], core_env["token"])
        assert result.status_code == 200
        assert len(result.data) == 2
        assert result.data[0]["date"] == "2021-11-11"
        assert result.data[0]["expense"] == 510.5

    @allure.title("03: get homepage info - bill monthly statistics ")
    @allure.story('story_1')
    def test_get_current_month_bill(self, core_env):
        result = bill_monthly_stat(core_env["date"], core_env["token"])
        assert result.status_code == 200
        assert result.data["expense"]
  • 其中core_env用于在接口间传递测试数据
// testcases -> scenario_test -> conftest.py
import pytest

@pytest.fixture(scope='session')
def core_env():
    return {"date": "2021-11"}

8. Allure生成测试报告

allure-pytest的详细使用方法可以参考官方文档。在这里只做简单介绍。

  • 运行测试时加上--alluredir参数可以生存报告到指定的文件夹:pytest --alluredir=/tmp/my_allure_results
  • 运行完后查看报告:allure serve /tmp/my_allure_results

下面是配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

软件测试面试小程序

被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!

涵盖以下这些面试题板块:

1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux

6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础

资料获取方式 :

猜你喜欢

转载自blog.csdn.net/myh919/article/details/131810989