温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Python中怎样实现参数化测试

发布时间:2021-07-05 17:33:19 来源:亿速云 阅读:206 作者:Leah 栏目:编程语言

Python中怎样实现参数化测试,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

1、什么是参数化测试?

对于普通测试来说,一个测试方法只需要运行一遍,而参数化测试对于一个测试方法,可能需要传入一系列参数,然后进行多次测试。

比如,我们要测试某个系统的登录功能,就可能要分别传入不同的用户名与密码,进行测试:使用包含非法字符的用户名、使用未注册的用户名、使用超长的用户名、使用错误的密码、使用合理的数据等等。

参数化测试是一种“数据驱动测试”(Data-Driven Test),在同一个方法上测试不同的参数,以覆盖所有可能的预期分支的结果。它的测试数据可以与测试行为分离,被放入文件、数据库或者外部介质中,再由测试程序读取。

2、参数化测试的实现思路?

通常而言,一个测试方法就是一个最小的测试单元,其功能应该尽量地原子化和单一化。

先来看看两种实现参数化测试的思路:一种是写一个测试方法,在其内部对所有测试参数进行遍历;另一种是在测试方法之外写遍历参数的逻辑,然后依次调用该测试方法。

这两种思路都能达到测试目的,在简单业务中,没有毛病。然而,实际上它们都只有一个测试单元,在统计测试用例数情况,或者生成测试报告的时候,并不乐观。可扩展性也是个问题。

那么,现有的测试框架是如何解决这个问题的呢?

它们都借助了装饰器,主要的思路是:利用原测试方法(例如 test()),来生成多个新的测试方法(例如 test1()、test2()……),并将参数依次赋值给它们。

由于测试框架们通常把一个测试单元统计为一个“test”,所以这种“由一生多”的思路相比前面的两种思路,在统计测试结果时,就具有很大的优势。

3、参数化测试的使用方法?

Python 标准库中的unittest 自身不支持参数化测试,为了解决这个问题,有人专门开发了两个库:一个是ddt ,一个是parameterized 。

ddt 正好是“Data-Driven Tests”(数据驱动测试)的缩写。典型用法:

import unittest  from ddt import ddt,data,unpack  @ddt  class MyTest(unittest.TestCase):      @data((3, 1), (-1, 0), (1.2, 1.0))      @unpack      def test_values(self, first, second):          self.assertTrue(first > second)  unittest.main(verbosity=2)

运行的结果如下:

test_values_1__3__1_ (__main__.MyTest) ... ok  test_values_2___1__0_ (__main__.MyTest) ... FAIL  test_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 wrapper      return func(self, *args, **kwargs)    File "C:/Users/pythoncat/PycharmProjects/study/testparam.py", line 9, in test_values      self.assertTrue(first > second)  AssertionError: False is not true  ----------------------------------------------  Ran 3 tests in 0.001s  FAILED (failures=1)

结果显示有 3 个 tests,并详细展示了运行状态以及断言失败的信息。

需要注意的是,这 3 个 test 分别有一个名字,名字中还携带了其参数的信息,而原来的 test_values 方法则不见了,已经被一拆为三。

在上述例子中,ddt 库使用了三个装饰器(@ddt、@data、@unpack),实在是很丑陋。下面看看相对更好用的 parameterized 库:

import unittest  from parameterized import parameterized  class MyTest(unittest.TestCase):      @parameterized.expand([(3,1), (-1,0), (1.5,1.0)])      def test_values(self, first, second):          self.assertTrue(first > second)  unittest.main(verbosity=2)

测试结果如下:

test_values_0 (__main__.MyTest) ... ok  test_values_1 (__main__.MyTest) ... FAIL  test_values_2 (__main__.MyTest) ... ok  =========================================  FAIL: test_values_1 (__main__.MyTest)  -----------------------------------------  Traceback (most recent call last):    File "C:\Python36\lib\site-packages\parameterized\parameterized.py", line 518, in standalone_func      return func(*(a + p.args), **p.kwargs)    File "C:/Users/pythoncat/PycharmProjects/study/testparam.py", line 7, in test_values      self.assertTrue(first > second)  AssertionError: False is not true  ----------------------------------------  Ran 3 tests in 0.000s  FAILED (failures=1)

这个库只用了一个装饰器 @parameterized.expand,写法上可就清爽多了。

同样提醒下,原来的测试方法已经消失了,取而代之的是三个新的测试方法,只是新方法的命名规则与 ddt 的例子不同罢了。

介绍完 unittest,接着看已经死翘翘了的nose 以及新生的nose2 。nose 系框架是带了插件(plugins)的 unittest,以上的用法是相通的。

另外,nose2 中还提供了自带的参数化实现:

import unittest  from nose2.tools import params  @params(1, 2, 3)  def test_nums(num):      assert num < 4  class Test(unittest.TestCase):      @params((1, 2), (2, 3), (4, 5))      def test_less_than(self, a, b):      assert a < b

最后,再来看下 pytest 框架,它这样实现参数化测试:

import pytest  @pytest.mark.parametrize("first,second", [(3,1), (-1,0), (1.5,1.0)])  def test_values(first, second):      assert(first > second)

测试结果如下:

==================== test session starts ====================  platform win32 -- Python 3.6.1, pytest-5.3.1, py-1.8.0, pluggy-0.13.1  rootdir: C:\Users\pythoncat\PycharmProjects\study collected 3 items  testparam.py .F  testparam.py:3 (test_values[-1-0])  first = -1, second = 0      @pytest.mark.parametrize("first,second", [(3,1), (-1,0), (1.5,1.0)])      def test_values(first, second):  >       assert(first > second)  E       assert -1 > 0  testparam.py:6: AssertionError  .                                                         [100%]  ========================= FAILURES ==========================  _________________________ test_values[-1-0] _________________________  first = -1, second = 0       @pytest.mark.parametrize("first,second", [(3,1), (-1,0), (1.5,1.0)])      def test_values(first, second):  >       assert(first > second)  E       assert -1 > 0  testparam.py:6: AssertionError  ===================== 1 failed, 2 passed in 0.08s =====================  Process finished with exit code 0

看完上述内容,你们掌握Python中怎样实现参数化测试的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI