前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关键字驱动框架

关键字驱动框架

作者头像
dongfanger
发布2023-12-05 14:15:23
1350
发布2023-12-05 14:15:23
举报
文章被收录于专栏:dongfangerdongfanger

关键字驱动框架

tep简介

tep是一款帮你轻松编写pytest的测试框架。Try Easy Pytest!

快速入门

安装

代码语言:javascript
复制
pip install tep

验证安装成功:

代码语言:javascript
复制
tep -V
代码语言:javascript
复制
Current Version: V2.2.0

 ____o__ __o____   o__ __o__/_   o__ __o
  /   \   /   \   <|    v       <|     v\
       \o/        < >           / \     <\
        |          |            \o/     o/
       < >         o__/_         |__  _<|/
        |          |             |
        o         <o>           <o>
       <|          |             |
       / \        / \  _\o__/_  / \

新建项目

代码语言:javascript
复制
tep new demo
代码语言:javascript
复制
Created folder: demo
Created folder: demo/case
Created folder: demo/data
Created folder: demo/data/har
Created folder: demo/report
Created file:   demo/replay.py
Created file:   demo/run.py
Created file:   demo/conftest.py
Created file:   demo/pytest.ini
Created file:   demo/.gitignore
Created file:   demo/case/__init__.py
Created file:   demo/case/test_demo.py
Created file:   demo/data/UserDefinedVariables.yaml

编写用例

先看个简单示例,在case/test_demo.py编写用例:

代码语言:javascript
复制
def test(HTTPRequestKeyword):
    response = HTTPRequestKeyword("get", url="http://httpbin.org/status/200")
    assert response.status_code == 200

执行run.py后出现以下日志:

代码语言:javascript
复制
URL: http://httpbin.org/status/200
Method: GET
Headers: {"User-Agent": "python-requests/2.31.0", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Connection": "keep-alive"}
Request Body: None
Status Code: 200
Response Body: 
Elapsed: 0.61046s

恭喜您,上手成功!

抓包自动生成用例

更简单点,抓包,自动生成用例。

编辑relay.py,指定HAR目录和用例目录:

代码语言:javascript
复制
import os

from tep.libraries.Config import Config
from tep.libraries.Har import Har

if __name__ == '__main__':
    profile = {
        "harDir": os.path.join(Config.BASE_DIR, "data", "har"),
        "desDir": os.path.join(Config.BASE_DIR, "case", "replay")
    }
    Har(profile).har2case()

默认HAR包放在data/har,生成用例放在case/replay

通过Proxyman、Charles等工具抓包后,导出HAR包到data/har目录中。如果还没来得及抓,可以下载现成的:

https://github.com/dongfanger/tep/blob/master/tests/demo/case/replay_demo.har

执行relay.py后就会自动生成replay_demo_test.py用例:

代码语言:javascript
复制
def test(HTTPRequestKeyword, JSONKeyword, VarKeyword):
    var = VarKeyword({})
    
    url = "http://httpbin.org/status/200"
    headers = JSONKeyword(r"""
{
    "Host":"httpbin.org",
    "Connection":"keep-alive",
    "accept":"text/plain",
    "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
    "Referer":"http://httpbin.org/",
    "Accept-Encoding":"gzip, deflate",
    "Accept-Language":"zh-CN,zh;q=0.9"
}
""")
    response = HTTPRequestKeyword("get", url=url, headers=headers)
    # user_defined_var = response.jsonpath("$.jsonpath")
    assert response.status_code < 400

让复杂的也变得简单,从登陆到下单示例:

代码语言:javascript
复制
def test(HTTPRequestKeyword, JSONKeyword, VarKeyword, login):
    headers = login()
    var = VarKeyword({
        "domain": "http://127.0.0.1:5000",
        "headers": headers
    })

    url = var["domain"] + "/searchSku" + "?skuName=book"
    response = HTTPRequestKeyword("get", url=url, headers=var["headers"])
    assert response.status_code < 400
    var["skuId"] = response.jsonpath("$.skuId")
    var["skuPrice"] = response.jsonpath("$.price")

    url = var["domain"] + "/addCart"
    body = JSONKeyword(r"""
{
    "skuId":"${skuId}",
    "skuNum":2
}
""")
    response = HTTPRequestKeyword("post", url=url, headers=var["headers"], json=body)
    assert response.status_code < 400
    var["skuNum"] = response.jsonpath("$.skuNum")
    var["totalPrice"] = response.jsonpath("$.totalPrice")

    url = var["domain"] + "/order"
    body = JSONKeyword(r"""
{
    "skuId":"${skuId}",
    "price":${skuPrice},
    "skuNum":${skuNum},
    "totalPrice":${totalPrice}
}
""")
    response = HTTPRequestKeyword("post", url=url, headers=var["headers"], json=body)
    assert response.status_code < 400
    var["orderId"] = response.jsonpath("$.orderId")

    url = var["domain"] + "/pay"
    body = JSONKeyword(r"""
{
    "orderId":"${orderId}",
    "payAmount":"0.2"
}
""")
    response = HTTPRequestKeyword("post", url=url, headers=var["headers"], json=body)
    assert response.status_code < 400
    assert response.jsonpath("$.success") == "true"

段落式组织代码,以关键字为驱动,pytest也可以写的很轻松。

目录结构

  • case 存放用例文件
  • data 存放数据文件
  • report 存放报告文件
  • replay.py 抓包自动生成用例
  • run.py 执行用例入口

用例管理

  1. 用例所在目录称之为用例集。
  2. 用例全部写在一个文件里面,从上往下分成多个段落,每个段落视为一个测试步骤。
  3. 测试步骤分为①前置②接口请求③后置三大部分。

前置示例:

代码语言:javascript
复制
headers = login()
var = VarKeyword({
    "domain": "http://127.0.0.1:5000",
    "headers": headers
})

接口请求示例:

代码语言:javascript
复制
url = var["domain"] + "/addCart"
body = JSONKeyword(r"""
{
    "skuId":"${skuId}",
    "skuNum":2
}
""")
response = HTTPRequestKeyword("post", url=url, headers=var["headers"], json=body)
assert response.status_code < 400

后置示例:

代码语言:javascript
复制
var["skuNum"] = response.jsonpath("$.skuNum")
var["totalPrice"] = response.jsonpath("$.totalPrice")

编写用例

手动编写

Python是解释性语言,py文件和yaml文件一样,顺序执行。简单写,简单执行。

①新建test_开头或_test结尾的py文件。

②定义函数:

代码语言:javascript
复制
def test():

③在函数参数中输入关键字:

代码语言:javascript
复制
def test(HTTPRequestKeyword):

PyCharm输入大写的K会出现语法提示,方便快速键入:

④编写请求:

代码语言:javascript
复制
def test(HTTPRequestKeyword):
    response = HTTPRequestKeyword("get", url="http://httpbin.org/status/200")

⑤添加断言:

代码语言:javascript
复制
def test(HTTPRequestKeyword):
    response = HTTPRequestKeyword("get", url="http://httpbin.org/status/200")
    assert response.status_code == 200

headers和body,使用多行字符串表示,通过JSONKeyword转为dict:

代码语言:javascript
复制
url = "https://postman-echo.com/post"
headers = JSONKeyword(r"""
{
    "Host":"postman-echo.com",
    "User-Agent":"Go-http-client/1.1",
    "Content-Length":"28",
    "Content-Type":"application/json; charset=UTF-8",
    "Cookie":"sails.sid=s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk",
    "Accept-Encoding":"gzip",
    "sails.sid":"s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk"
}
""")
body = JSONKeyword(r"""
{
    "foo1":"HDnY8",
    "foo2":12.3
}
""")
response = HTTPRequestKeyword("post", url=url, headers=headers, json=body)

HAR包转换

单个文件

代码语言:javascript
复制
import os

from tep.libraries.Config import Config
from tep.libraries.Har import Har


def test():
    profile = {
        "harFile": os.path.join(Config.BASE_DIR, "case", "replay_demo.har")
    }
    Har(profile).har2case()

指定目录

代码语言:javascript
复制
import os

from tep.libraries.Config import Config
from tep.libraries.Har import Har

if __name__ == '__main__':
    profile = {
        "harDir": os.path.join(Config.BASE_DIR, "data", "har"),
        "desDir": os.path.join(Config.BASE_DIR, "case", "replay")
    }
    Har(profile).har2case()

如果HAR包已经生成了用例,第二次执行会跳过。通过配置overwrite: True可重新覆盖:

代码语言:javascript
复制
import os

from tep.libraries.Config import Config
from tep.libraries.Har import Har

if __name__ == '__main__':
    profile = {
        "harDir": os.path.join(Config.BASE_DIR, "data", "har"),
        "desDir": os.path.join(Config.BASE_DIR, "case", "replay"),
        "overwrite": True
    }
    Har(profile).har2case()

回放对比

profile配置"replay": True,开启回放对比:

代码语言:javascript
复制
import os

from loguru import logger

from tep.libraries.Config import Config
from tep.libraries.Har import Har


def test():
    har_file = os.path.join(Config.BASE_DIR, "case", "har", "demo.har")
    profile = {"replay": True}
    Har(har_file, profile).har2case()

等待HAR包转换为pytest用例后,执行pytest用例,即会对比:

变量管理

全局变量data/UserDefinedVariables.yaml中定义,通过UserDefinedVariablesKeyword关键字读取。

局部变量test()函数内定义,通过VarKeyword关键字设值和取值。

其他维度变量可在data目录下新建YAML/JSON文件,通过DataKeyword读取。

接口关联

初始化

test()函数中通过VarKeyword关键字初始化一个变量池:

代码语言:javascript
复制
var = VarKeyword({})

取值

在步骤后置中通过jsonpath取值:

代码语言:javascript
复制
var["skuId"] = response.jsonpath("$.skuId")

存入变量池中。

传值

通过JSONKeyword关键字,在字符串中使用${}标记变量:

代码语言:javascript
复制
body = JSONKeyword(r"""
{
    "skuId":"${skuId}",
    "skuNum":2
}
""")

框架会使用变量池中同名变量进行替换。

数据管理

PyCharm就是“测试平台”,单个用例文件就是平台界面,数据和代码都写在里面。

若要分离,可从文件读取。

接口管理

以空间换时间,接口不单独管理,跟随用例复制多份,用例维护自己的接口参数。

若要复用,自定义关键字。

原生断言

代码语言:javascript
复制
def test_assert_equal():
    assert 1 == 1


def test_assert_not_equal():
    assert 1 != 2


def test_assert_greater_than():
    assert 2 > 1


def test_assert_less_than():
    assert 1 < 2


def test_assert_less_or_equals():
    assert 2 >= 1
    assert 2 >= 2


def test_assert_greater_or_equals():
    assert 1 <= 2
    assert 1 <= 1


def test_assert_length_equal():
    assert len("abc") == len("123")


def test_assert_length_greater_than():
    assert len("hello") > len("123")


def test_assert_length_less_than():
    assert len("hi") < len("123")


def test_assert_length_greater_or_equals():
    assert len("hello") >= len("123")
    assert len("123") >= len("123")


def test_assert_length_less_or_equals():
    assert len("123") <= len("hello")
    assert len("123") <= len("123")


def test_assert_string_equals():
    assert "dongfanger" == "dongfanger"


def test_assert_startswith():
    assert "dongfanger".startswith("don")


def test_assert_regex_match():
    import re
    assert re.findall(r"don.*er", "dongfanger")


def test_assert_contains():
    assert "fang" in "dongfanger"
    assert 2 in [2, 3]
    assert "x" in {"x": "y"}.keys()


def test_assert_type_match():
    assert isinstance(1, int)
    assert isinstance(0.2, float)
    assert isinstance(True, bool)
    assert isinstance(3e+26j, complex)
    assert isinstance("hi", str)
    assert isinstance([1, 2], list)
    assert isinstance((1, 2), tuple)
    assert isinstance({"a", "b", "c"}, set)
    assert isinstance({"x": 1}, dict)

测试报告

支持pytst-html报告和Allure报告。

默认为pytest-html,无需单独安装。

Allure需要安装Java,下载Allure安装包,解压后将bin目录添加到系统环境变量Path:

https://github.com/allure-framework/allure2/releases

协议支持

默认协议为HTTP1,添加http2=True参数后,使用HTTP2协议:

代码语言:javascript
复制
def test(HTTPRequestKeyword):
    ro = HTTPRequestKeyword("get", url="http://httpbin.org/status/200", http2=True)
    assert ro.response.status_code == 200

HAR包转换用例时,在profile配置"http2": True也能使用HTTP2协议。

接口重试

给用例添加@retry,自定义重试策略,比如重试3次,间隔2秒。

根据CODE码进行重试:

代码语言:javascript
复制
from loguru import logger
from tenacity import retry, stop_after_attempt, wait_fixed


@retry(
    stop=stop_after_attempt(3),
    wait=wait_fixed(2),
    before=lambda _: logger.info("Retrying..."),
    after=lambda _: logger.info("Retry completed.")
)
def test(HTTPRequestKeyword):
    ro = HTTPRequestKeyword("get", url="http://127.0.0.1:5000/retry/code")
    ro.response.raise_for_status()  # Add this statement

根据Exception类型进行重试:

代码语言:javascript
复制
from loguru import logger
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type


@retry(
    stop=stop_after_attempt(3),
    wait=wait_fixed(2),
    retry=retry_if_exception_type(TypeError),
    before=lambda _: logger.info("Retrying..."),
    after=lambda _: logger.info("Retry completed.")
)
def test_exception(HTTPRequestKeyword):
    ro = HTTPRequestKeyword("get", url="http://127.0.0.1:5000/retry/200")
    raise TypeError

关键字

关键字的本质是pytest fixture函数。

内置关键字

命名方式:大驼峰命名,Keyword结尾

HTTPRequestKeyword

与requests.request用法完全一致

JSONKeyword

将字符串转为dict,支持${}替换变量

UserDefinedVariablesKeyword

读取data/UserDefinedVariables.yaml作为全局变量

DataKeyword

读取data目录下YAML/JSON文件作为自定义变量

自定义关键字

命名方式:下划线命名。

自定义关键字需新建fixture包,文件名以fixture_开头:

login

登录接口,可定义为全局只登陆一次

mysql_execute

连接MySQL数据库,执行SQL语句

关键字使用示例请查看https://github.com/dongfanger/tep/tree/master/tests/demo/case:

源码地址

https://github.com/dongfanger/tep

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-12-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关键字驱动框架
    • tep简介
      • 快速入门
        • 安装
        • 新建项目
        • 编写用例
        • 抓包自动生成用例
      • 目录结构
        • 用例管理
          • 编写用例
            • 手动编写
            • HAR包转换
            • 回放对比
          • 变量管理
            • 接口关联
              • 数据管理
                • 接口管理
                  • 原生断言
                    • 测试报告
                      • 协议支持
                        • 接口重试
                          • 关键字
                            • 内置关键字
                            • 自定义关键字
                          • 源码地址
                          相关产品与服务
                          云数据库 MySQL
                          腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档