百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

用 Python 为接口测试自动生成用例

off999 2024-12-09 16:18 17 浏览 0 评论

基于属性的测试会产生大量的、随机的参数,特别适合为单元测试和接口测试生成测试用例

尽管早在2006年haskell语言就有了QuickCheck来进行”基于属性的测试“,但是目前来看这依然是一个比较小众的领域,参考资料有限,本文如有不足,欢迎指正。


1. 基于表的测试

在过去的测试实践中,执行测试时通常需要明确的内容(Value):

  1. 条件
  2. 输入
  3. 结果

这些内容可以通过”判定树“或者”判断表“来表示,然后测试的执行过程变成了这样

“给定输入 X,我们期望 Y”

可以称为 基于表的测试

在最初,这给了我们测试的方向,但是缺点也非常明显:

你要足够多的"X->Y" 才能可能覆盖到隐蔽的bug。

这里请大家回答几个问题:

你是否已经为每一个测试编写了足够多的用例,以至于你十分确定真的不需要再增加用例了这么多的用例,你编写的是否开心?是否高效?是否愿意继续坚持?

如果以上问题的答案不是yes,那么基于属性的测试就是你需要掌握的东西!


2. 基于属性的测试

基于属性的测试和基于表的测试,最大的区别可以这样描述:

“给定输入 X值,我们期望 Y值”

vs

“给定输入 X类,我们期望 Y类”

于是利用工具生成大量的X类数据,进行测试,并验证结果是否Y类。

值得注意的是:

  1. 关注输入的类型,而不是输入的值
  2. 根据类型自动生成大量的、随机的输入值

换言之,它在自动的生成测试用例,虽然输入值是随机的,但是值得类型符合规范要求


3. 如何进行基于属性的测试

在不同的语言中有不同的工具来实现,比如:

  • haskell中的QuickCheck
  • java中的quicktheories
  • python中的hypothesis

本文以python为例进行演示:

假设有add函数,接收两个类型整数参数,并返回它们的相加结果

def add(a: int, b: int) -> int:
    pass

首先写出一个简单的测试用例

def test_add():
    assert 3 == add(1, 2)

正如前面所说,一个这样的用例,根本没信心覆盖全部的场景,例如:

  • 参数是0
  • 参数是负数
  • 参数值特别大
  • 其他...

所以接下来怎么办?

改为基于属性的测试

import hypothesis.strategies as st
from hypothesis import given

@given(st.integers(), st.integers())
def test_add(a, b):
    c = add(a, b)
    print(f"{a=},{b=}, {c=}")
    assert isinstance(c, int)
    assert c == a + b

执行结果

 a=0,b=0, c=0
a=0,b=0, c=0
a=0,b=0, c=0
a=16926,b=11053, c=27979
a=0,b=0, c=0
a=0,b=0, c=0
a=21010,b=-2732672789497425072, c=-2732672789497404062
a=0,b=0, c=0
a=14554,b=-15956, c=-1402
a=15597,b=0, c=15597
a=15597,b=13, c=15610
a=15597,b=0, c=15597
a=15597,b=15597, c=31194
a=28965,b=-36, c=28929
a=113,b=-36, c=77
a=28929,b=-36, c=28893
a=28929,b=9356, c=38285
a=9356,b=9356, c=18712
a=10278,b=-62, c=10216
a=-62,b=-62, c=-124
a=1625,b=-68244995710046113596363052355575247332, c=-68244995710046113596363052355575245707
a=1625,b=-13143, c=-11518
a=1625,b=1625, c=3250
a=-1940,b=-31868, c=-33808
a=-7,b=1, c=-6
a=-1,b=0, c=-1
a=-1,b=0, c=-1
a=13,b=7245, c=7258
a=13,b=13, c=26
a=-99,b=-18, c=-117
a=-30172,b=66, c=-30106
a=-30172,b=-16940, c=-47112
a=-16940,b=-16940, c=-33880
a=-1233214851,b=-5152, c=-1233220003
a=-5152,b=-5152, c=-10304
a=-16,b=-29706, c=-29722
a=-29706,b=-29706, c=-59412
a=-29706,b=116, c=-29590
a=29696,b=90, c=29786
a=29696,b=29696, c=59392
a=-11446,b=-21185, c=-32631
a=-21185,b=-21185, c=-42370
a=-12,b=16437, c=16425
a=-12,b=16437, c=16425
a=3202,b=53, c=3255
a=3202,b=3202, c=6404
a=-98,b=3, c=-95
a=82691970030325711417874227410289695610,b=1316378701, c=82691970030325711417874227411606074311
a=82691970030325711417874227410289695610,b=82691970030325711417874227410289695610, c=165383940060651422835748454820579391220
a=24100,b=14385, c=38485
a=24100,b=14385, c=38485
a=24100,b=24100, c=48200
a=12293,b=-106, c=12187
a=12293,b=27280, c=39573
a=27280,b=27280, c=54560
a=-18887,b=-5530, c=-24417
a=-18887,b=-18887, c=-37774
a=4738,b=122351151658095310625663643505383743930, c=122351151658095310625663643505383748668
a=-24601163521689169516616964879873921492,b=565838202, c=-24601163521689169516616964879308083290
a=4738,b=122351151658095310625663643281738736058, c=122351151658095310625663643281738740796
a=-96098295006598318424285019062007505,b=25207226, c=-96098295006598318424285019036800279
a=-96098295006598318424285019062007505,b=-1997122225172868107163535967078611096, c=-2093220520179466425587820986140618601
a=-96098295006598318424285019062007505,b=-96098295006598318424285019062007505, c=-192196590013196636848570038124015010
a=-36,b=1190, c=1154
a=-36,b=-4, c=-40
a=-36,b=-36, c=-72
a=2047897602,b=-4641, c=2047892961
a=2047897602,b=2047897602, c=4095795204
a=-1307873608,b=11753, c=-1307861855
a=-1307873608,b=-3308225400997338452, c=-3308225402305212060
a=-1307873608,b=770256249, c=-537617359
a=-1307873608,b=-1307873608, c=-2615747216
a=-4715910568460396013,b=-18622, c=-4715910568460414635
a=16754,b=-6053, c=10701
a=-6053,b=-6053, c=-12106
a=-6053,b=-6053, c=-12106
a=-22264,b=44, c=-22220
a=-22264,b=-22264, c=-44528
a=-86,b=-86, c=-172
a=-86,b=-86, c=-172
a=1794,b=28170, c=29964
a=1794,b=28170, c=29964
a=-93,b=482, c=389
a=-1,b=482, c=481
a=-1,b=-1, c=-2

由结果可知,工具根据参数是整数这一规范,自动生成、执行了大量的测试用例


4. 在接口测试中自动生成用例

接口测试和函数的单元测试非常相似:

  • 输入数据
  • 返回数据

此外接口文档作为前后端、甚至测试开发的对接窗口,对参数的要求约定的更加细致,

以OpenAPI为例,每个参数可以有以下属性:

  • type:数字还是字符串?
  • format:密码还是电子邮箱?
  • maxLength:长度不超过多少?
  • required:是否必填?
  • in:参数通过什么传递?
  • 其他...

于是为接口生成符合要求的参数就变得可行了,举个例子:

import logging
import unittest

import requests

from api_tools import APITestCase



class UserCase(APITestCase):
    schema = "http://127.0.0.1:7600/openapi.json"

if __name__ == "__main__":
    unittest.main()

这是以unittest为例进行封装的结果,只需要在TestCase中指定openapi的内容(或路径),

启动测试框架时,会自动读取、解析接口文档,并生成测试用例

下面是部分执行日志,可以看到对接口发送了随机参数,并获得返回值

INFO     2022-04-10 01:02:59,223 : 执行用例 login_login_access_token_post
INFO     2022-04-10 01:02:59,223 : -----调用接口:login_login_access_token_post-----
INFO     2022-04-10 01:02:59,223 : 发送请求>>>   :请求数据 = {'userin': {'password': 'bEYtwDZUxdBVThEFOqTz', 'email': 'KEfQnAtTNtwZOXRjoIjp'}}
INFO     2022-04-10 01:02:59,578 : 接收响应   <<<: <Response [400]>
INFO     2022-04-10 01:02:59,578 : -----调用完毕:login_login_access_token_post-----
INFO     2022-04-10 01:02:59,578 : 执行用例 test_token_login_test_token_post
INFO     2022-04-10 01:02:59,578 : -----调用接口:test_token_login_test_token_post-----
INFO     2022-04-10 01:02:59,578 : 发送请求>>>   :请求数据 = {}
INFO     2022-04-10 01:03:00,035 : 接收响应   <<<: <Response [200]>
INFO     2022-04-10 01:03:00,035 : -----调用完毕:test_token_login_test_token_post-----
INFO     2022-04-10 01:03:00,035 : 执行用例 sign_up_login_sign_up_post
INFO     2022-04-10 01:03:00,035 : -----调用接口:sign_up_login_sign_up_post-----
INFO     2022-04-10 01:03:00,035 : 发送请求>>>   :请求数据 = {'userin': {'password': 'GgzYcOwapTwnkkKVTraE', 'email': 'EJrXlCSNKKjdiVvAOnTM'}}
INFO     2022-04-10 01:03:00,657 : 接收响应   <<<: <Response [200]>
INFO     2022-04-10 01:03:00,657 : -----调用完毕:sign_up_login_sign_up_post-----
INFO     2022-04-10 01:03:00,657 : 执行用例 todo_list_todo_get
INFO     2022-04-10 01:03:00,657 : -----调用接口:todo_list_todo_get-----
INFO     2022-04-10 01:03:00,657 : 发送请求>>>   :请求数据 = {}
INFO     2022-04-10 01:03:01,233 : 接收响应   <<<: <Response [200]>
INFO     2022-04-10 01:03:01,233 : -----调用完毕:todo_list_todo_get-----
INFO     2022-04-10 01:03:01,233 : 执行用例 todo_post_todo_post
INFO     2022-04-10 01:03:01,233 : -----调用接口:todo_post_todo_post-----
INFO     2022-04-10 01:03:01,233 : 发送请求>>>   :请求数据 = {'todoin': {'title': '', 'is_done': False}}
INFO     2022-04-10 01:03:01,594 : 接收响应   <<<: <Response [200]>
INFO     2022-04-10 01:03:01,594 : -----调用完毕:todo_post_todo_post-----
INFO     2022-04-10 01:03:01,594 : 执行用例 todo_delete_all_todo_delete
INFO     2022-04-10 01:03:01,594 : 执行用例 todo_get_todo__todo_id__get
INFO     2022-04-10 01:03:01,594 : -----调用接口:todo_get_todo__todo_id__get-----
INFO     2022-04-10 01:03:01,594 : 发送请求>>>   :请求数据 = {'todo_id': 2451}
INFO     2022-04-10 01:03:02,026 : 接收响应   <<<: <Response [404]>
INFO     2022-04-10 01:03:02,026 : -----调用完毕:todo_get_todo__todo_id__get-----
INFO     2022-04-10 01:03:02,026 : 执行用例 todo_put_todo__todo_id__put
INFO     2022-04-10 01:03:02,026 : -----调用接口:todo_put_todo__todo_id__put-----
INFO     2022-04-10 01:03:02,026 : 发送请求>>>   :请求数据 = {'todo_id': 1519, 'todoin': {'title': '', 'is_done': False}}
INFO     2022-04-10 01:03:02,423 : 接收响应   <<<: <Response [404]>
INFO     2022-04-10 01:03:02,423 : -----调用完毕:todo_put_todo__todo_id__put-----
INFO     2022-04-10 01:03:02,423 : 执行用例 

文章来自https://www.cnblogs.com/dongfangtianyu/p/api_test_by_pbt.html

相关推荐

独家 | 5 个Python高级特性让你在不知不觉中成为Python高手

你已经使用Python编程了一段时间,编写脚本并解决各种问题。是你的水平出色吗?你可能只是在不知不觉中利用了Python的高级特性。从闭包(closure)到上下文管理器(contextmana...

Python装饰器

Python装饰器是一种用于修改函数或类的行为的特殊语法。它们允许在不修改原始代码的情况下,通过将函数或类作为参数传递给另一个函数来添加额外的功能。装饰器本质上是一个函数,它接受一个函数作为参数,并返...

中高阶Python常规用法--上下文管理器

Python以简单性和通用性著称,是一种深受全球开发人员喜爱的编程语言。它提供了大量的特性和功能,使编码成为一种愉快的体验。在这些功能中,一个经常被新手忽视的强大工具是上下文管理器。上下文管理器是高...

Python小案例67- 装饰器

Python装饰器是一种用于修改函数或类的行为的特殊语法。它们允许在不修改原始代码的情况下,通过将函数或类作为参数传递给另一个函数来添加额外的功能。装饰器本质上是一个函数,它接受一个函数作为参数,并返...

python常用的语法糖

概念Python的语法糖(SyntacticSugar)是指那些让代码更简洁、更易读的语法特性,它们本质上并不会增加新功能,但能让开发者更高效地编写代码。推导式写法推导式是Python最经典的...

python - 常用的装饰器 decorator 有哪些?

python编程中使用装饰器(decorator)工具,可以使代码更简洁清晰,提高代码的重用性,还可以为代码维护提供方便。对于python初学者来说,根据装饰器(decorator)的字面意思并不...

python数据缓存怎么搞 ?推荐一个三方包供你参考,非常简单好用。

1.数据缓存说明数据缓存可以说也是项目开发中比不可少的一个工具,像我们测试的系统中,你都会见到像Redis一样的数据缓存库。使用缓存数据库的好处不言而喻,那就是效率高,简单数据直接放在缓存中...

用于时间序列数据的Graphite监视工具

结合第三方工具,Graphite为IT性能监控提供了许多好处。本文介绍其核心组件,包括Carbon、Whisper以及安装的基本准则。Graphite监视工具可实时或按需,大规模地绘制来自多个来源的时...

Python3+pygame实现的坦克大战

一、显示效果二、代码1.说明几乎所有pygame游戏,基本都遵循一定的开发流程,大体如下:初始化pygame创建窗口while循环检测以及处理事件(鼠标点击、按键等)更新UI界面2.代码创建一个m...

Python之鸭子类型:一次搞懂with与上下文装饰器

引言在鸭子类型的理念的基础之上,从关注类型,转变到关注特性和行为。结合Python中的魔法函数的体系,我们可以将自定义的类型,像内置类型一样被使用。今天这篇文章中,接着该话题,继续聊一下with语法块...

Python必会的50个代码操作

学习Python时,掌握一些常用的程序操作非常重要。以下是50个Python必会的程序操作,主要包括基础语法、数据结构、函数和文件操作等。1.HelloWorldprint("Hello,...

一文掌握Python 中的同步和异步

同步代码(Sync)同步就像在一个流水线上工作,每个任务都等待前一个任务完成。示例:机器A切割钢板→完成后,机器B钻孔→完成后,机器C上色。在Python中,同步代码看起来像这样:im...

python 标注模块timeit: 测试函数的运行时间

在Python中,可以使用内置的timeit模块来测试函数的运行时间。timeit模块提供了一个简单的接口来测量小段代码的执行时间。以下是使用timeit测试函数运行时间的一般步骤:导入...

Python带你找回童年的万花尺

还记得小时候的万花尺吧?这么画:一点也不费脑筋,就可以出来这么多丰富多彩的复杂几何图形。具体而言,可以用万花尺玩具(如图2-1所示)来绘制数学曲线。这种玩具由两个不同尺寸的塑料齿轮组成,一大一小。小的...

Python 时间模块深度解析:从基础到高级的全面指南

直接上干货一、时间模块核心类介绍序号类名说明1datetime.datetime表示一个具体的日期和时间,结合了日期和时间的信息。2datetime.date表示一个具体的日期。3datetime.t...

取消回复欢迎 发表评论: