心若磐石|Python 中如何实现参数化测试?

优质文章 , 第一时间送达!
心若磐石|Python 中如何实现参数化测试?本文想针对测试中一种很常见的测试场景 , 即参数化测试 , 聊聊关于测试的话题 , 并尝试将这几个测试框架串联起来 , 做一个横向的比对 , 加深理解 。
1、什么是参数化测试?对于普通测试来说 , 一个测试方法只需要运行一遍 , 而参数化测试对于一个测试方法 , 可能需要传入一系列参数 , 然后进行多次测试 。
比如 , 我们要测试某个系统的登录功能 , 就可能要分别传入不同的用户名与密码 , 进行测试:使用包含非法字符的用户名、使用未注册的用户名、使用超长的用户名、使用错误的密码、使用合理的数据等等 。
参数化测试是一种“数据驱动测试”(Data-Driven Test) , 在同一个方法上测试不同的参数 , 以覆盖所有可能的预期分支的结果 。 它的测试数据可以与测试行为分离 , 被放入文件、数据库或者外部介质中 , 再由测试程序读取 。
2、参数化测试的实现思路?通常而言 , 一个测试方法就是一个最小的测试单元 , 其功能应该尽量地原子化和单一化 。
【心若磐石|Python 中如何实现参数化测试?】先来看看两种实现参数化测试的思路:一种是写一个测试方法 , 在其内部对所有测试参数进行遍历;另一种是在测试方法之外写遍历参数的逻辑 , 然后依次调用该测试方法 。
这两种思路都能达到测试目的 , 在简单业务中 , 没有毛病 。 然而 , 实际上它们都只有一个测试单元 , 在统计测试用例数情况 , 或者生成测试报告的时候 , 并不乐观 。 可扩展性也是个问题 。
那么 , 现有的测试框架是如何解决这个问题的呢?
它们都借助了装饰器 , 主要的思路是:利用原测试方法(例如 test()) , 来生成多个新的测试方法(例如 test1()、test2()……) , 并将参数依次赋值给它们 。
由于测试框架们通常把一个测试单元统计为一个“test” , 所以这种“由一生多”的思路相比前面的两种思路 , 在统计测试结果时 , 就具有很大的优势 。
3、参数化测试的使用方法?Python 标准库中的unittest自身不支持参数化测试 , 为了解决这个问题 , 有人专门开发了两个库:一个是ddt , 一个是parameterize
ddt 正好是“Data-Driven Tests”(数据驱动测试)的缩写 。 典型用法:
import unittestfrom ddt import ddt,data,unpack@ddtclass MyTest(unittest.TestCase):@data((3, 1), (-1, 0), (1.2, 1.0))@unpackdef test_values(self, first, second):self.assertTrue(first > second)unittest.main(verbosity=2)运行的结果如下:
test_values_1__3__1_ (__main__.MyTest) ... oktest_values_2___1__0_ (__main__.MyTest) ... FAILtest_values_3__1_2__1_0_ (__main__.MyTest) ... ok==================================================FAIL: test_values_2___1__0_ (__main__.MyTest)--------------------------------------------------Traceback (most recent call last):File "C:\Python36\lib\site-packages\ddt.py", line 145, in wrapperreturn func(self, *args, **kwargs)File "C:/Users/pythoncat/PycharmProjects/study/testparam.py", line 9, in test_valuesself.assertTrue(first > second)AssertionError: False is not true----------------------------------------------Ran 3 tests in 0.001sFAILED (failures=1)结果显示有 3 个 tests , 并详细展示了运行状态以及断言失败的信息 。
需要注意的是 , 这 3 个 test 分别有一个名字 , 名字中还携带了其参数的信息 , 而原来的 test_values 方法则不见了 , 已经被一拆为三 。


推荐阅读