前言

unittest单元测试框架使用DDT进行数据驱动测试,那么身为功能更加强大且更加灵活的Pytest框架怎么可能没有数据驱动的概念呢?其实Pytest是使用@pytest.mark.parametrize装饰器来实现数据驱动测试的,那么今天我们就简单来说说在它是如何进行数据驱动测试的

装饰测试类

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data_1 = [
  15. (1, 2, 3),
  16. (4, 5, 9)
  17. ]
  18.  
  19. def add(a, b):
  20. return a + b
  21.  
  22. @pytest.mark.parametrize('a, b, expect', data_1)
  23. class TestParametrize(object):
  24.  
  25. def test_parametrize_1(self, a, b, expect):
  26. print('\n测试函数1测试数据为\n{}-{}'.format(a, b))
  27. assert add(a, b) == expect
  28.  
  29. def test_parametrize_2(self, a, b, expect):
  30. print('\n测试函数2数据为\n{}-{}'.format(a, b))
  31. assert add(a, b) == expect
  32.  
  33. if __name__ == '__main__':
  34. pytest.main(['-sv'])

输出

  1. collecting ... collected 4 items
  2.  
  3. test_parametrize.py::TestParametrize::test_parametrize_1[1-2-3]
  4. 测试函数1测试数据为
  5. 1-2
  6. PASSED
  7. test_parametrize.py::TestParametrize::test_parametrize_1[4-5-9]
  8. 测试函数1测试数据为
  9. 4-5
  10. PASSED
  11. test_parametrize.py::TestParametrize::test_parametrize_2[1-2-3]
  12. 测试函数2数据为
  13. 1-2
  14. PASSED
  15. test_parametrize.py::TestParametrize::test_parametrize_2[4-5-9]
  16. 测试函数2数据为
  17. 4-5
  18. PASSED
  19.  
  20. ========================== 4 passed in 0.21 seconds ===========================
  21.  
  22. Process finished with exit code 0

说明

当装饰器装饰测试类时,给数据集合会被传递给给类的所有方法

装饰测试函数

单个数据

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data = [1, 2]
  15.  
  16. @pytest.mark.parametrize('a', data)
  17. def test_parametrize(a):
  18. print('\n被加载测试数据为\n{}'.format(a))
  19.  
  20. if __name__ == '__main__':
  21. pytest.main(['-s'])

输出

  1. ============================= test session starts =============================
  2. platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
  3. rootdir: E:\CnblogCode\pytest_parametrize, inifile:
  4. plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
  5. collected 2 items
  6.  
  7. test_parametrize.py
  8. 被加载测试数据为
  9. 1
  10. .
  11. 被加载测试数据为
  12. 2
  13. .
  14.  
  15. ========================== 2 passed in 0.16 seconds ===========================
  16.  
  17. Process finished with exit code 0

说明

当测试用例只需要一个参数时,我们存放数据的列表无序嵌套序列,@pytest.mark.parametrize('a', data)装饰器的第一个参数也只需要一个变量接收列表中的每个元素,第二个参数传递存储数据的列表,那么测试用例需要使用同名的字符串接收测试数据(实例中的a)且列表有多少个元素就会生成并执行多少个测试用例

一组数据

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data = [
  15. [1, 2, 3],
  16. [4, 5, 9]
  17. ] # 列表嵌套列表
  18. # data_tuple = [
  19. # (1, 2, 3),
  20. # (4, 5, 9)
  21. # ] # 列表嵌套元组
  22.  
  23. @pytest.mark.parametrize('a, b, expect', data)
  24. def test_parametrize_1(a, b, expect): # 一个参数接收一个数据
  25. print('\n测试数据为\n{},{},{}'.format(a, b, expect))
  26. actual = a + b
  27. assert actual == expect
  28.  
  29. @pytest.mark.parametrize('value', data)
  30. def test_parametrize_2(value): # 一个参数接收一组数据
  31. print('\n测试数据为\n{}'.format(value))
  32. actual = value[0] + value[1]
  33. assert actual == value[2]
  34.  
  35. if __name__ == '__main__':
  36. pytest.main(['-s'])

输出

  1. ============================= test session starts =============================
  2. platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
  3. rootdir: E:\CnblogCode\pytest_parametrize, inifile:
  4. plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
  5. collected 4 items
  6.  
  7. test_parametrize.py
  8. 测试数据为
  9. 123
  10. .
  11. 测试数据为
  12. 459
  13. .
  14. 测试数据为
  15. [1, 2, 3]
  16. .
  17. 测试数据为
  18. [4, 5, 9]
  19. .
  20.  
  21. ========================== 4 passed in 0.17 seconds ===========================
  22.  
  23. Process finished with exit code 0

说明

当测试用例需要多个数据时,我们可以使用嵌套序列(嵌套元组&嵌套列表)的列表来存放测试数据

装饰器@pytest.mark.parametrize()可以使用单个变量接收数据,也可以使用多个变量接收,同样,测试用例函数也需要与其保持一致

当使用单个变量接收时,测试数据传递到测试函数内部时为列表中的每一个元素或者小列表,需要使用索引的方式取得每个数据

当使用多个变量接收数据时,那么每个变量分别接收小列表或元组中的每个元素

列表嵌套多少个多组小列表或元组,测生成多少条测试用例

图解对应关系

组合数据

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data_1 = [1, 2]
  15. data_2 = [3, 4]
  16.  
  17. @pytest.mark.parametrize('a', data_1)
  18. @pytest.mark.parametrize('b', data_2)
  19. def test_parametrize_1(a, b):
  20. print('\n测试数据为\n{},{}'.format(a, b))
  21.  
  22. if __name__ == '__main__':
  23. pytest.main(['-s'])

输出

  1. ============================= test session starts =============================
  2. platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
  3. rootdir: E:\CnblogCode\pytest_parametrize, inifile:
  4. plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
  5. collected 4 items
  6.  
  7. test_parametrize.py
  8. 测试数据为
  9. 13
  10. .
  11. 测试数据为
  12. 23
  13. .
  14. 测试数据为
  15. 14
  16. .
  17. 测试数据为
  18. 24
  19. .
  20.  
  21. ========================== 4 passed in 0.24 seconds ===========================
  22.  
  23. Process finished with exit code 0

说明

通过测试结果,我们不难分析,一个测试函数还可以同时被多个参数化装饰器装饰,那么多个装饰器中的数据会进行交叉组合的方式传递给测试函数,进而生成n*n个测试用例,这也为我们的测试设计时提供了方便

标记用例

可以直接标记测试用例,参数化装饰器也可以识别(标记用例失败或跳过)

标记为无条件跳过(标记为失败为xfail,自己尝试)

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data_1 = [
  15. [1, 2, 3],
  16. pytest.param(3, 4, 8, marks=pytest.mark.skip)
  17. ]
  18.  
  19. def add(a, b):
  20. return a + b
  21.  
  22. @pytest.mark.parametrize('a, b, expect', data_1)
  23. def test_parametrize_1(a, b, expect):
  24. print('\n测试数据为\n{},{}'.format(a, b))
  25. assert add(a, b) == expect
  26.  
  27. if __name__ == '__main__':
  28. pytest.main(['-vs'])

输出

  1. ============================= test session starts =============================
  2. platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 -- C:\Programs\Python\Python37-32\python.exe
  3. cachedir: .pytest_cache
  4. metadata: {'Python': '3.7.2', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'pytest': '4.3.1', 'py': '1.8.0', 'pluggy': '0.9.0'}, 'Plugins': {'rerunfailures': '7.0', 'metadata': '1.8.0', 'html': '1.20.0'}, 'JAVA_HOME': 'D:\\JDK'}
  5. rootdir: E:\CnblogCode\pytest_parametrize, inifile:
  6. plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
  7. collecting ... collected 2 items
  8.  
  9. test_parametrize.py::test_parametrize_1[1-2-3]
  10. 测试数据为
  11. 12
  12. PASSED
  13. test_parametrize.py::test_parametrize_1[3-4-8] SKIPPED
  14.  
  15. ===================== 1 passed, 1 skipped in 0.17 seconds =====================
  16.  
  17. Process finished with exit code 0

说明

输出结果显示收集到2个用例,一个通过,一个被跳过,当我们不想执行某组测试数据时,我们可以标记skip或skipif;当我们预期某组数据会执行失败时,我们可以标记为xfail等

嵌套字典

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data_1 = (
  15. {
  16. 'user': 1,
  17. 'pwd': 2
  18. },
  19. {
  20. 'user': 3,
  21. 'pwd': 4
  22. }
  23. )
  24.  
  25. @pytest.mark.parametrize('dic', data_1)
  26. def test_parametrize_1(dic):
  27. print('\n测试数据为\n{}'.format(dic))
  28.  
  29. if __name__ == '__main__':
  30. pytest.main(['-s'])

输出

  1. ============================= test session starts =============================
  2. platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
  3. rootdir: E:\CnblogCode\pytest_parametrize, inifile:
  4. plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
  5. collected 2 items
  6.  
  7. test_parametrize.py
  8. 测试数据为
  9. {'user': 1, 'pwd': 2}
  10. .
  11. 测试数据为
  12. {'user': 3, 'pwd': 4}
  13. .
  14.  
  15. ========================== 2 passed in 0.20 seconds ===========================
  16.  
  17. Process finished with exit code 0

增加可读性

使用ids参数

参数化装饰器有一个额外的参数ids,可以标识每一个测试用例,自定义测试数据结果的显示,为了增加可读性,我们可以标记每一个测试用例使用的测试数据是什么,适当的增加一些说明

在使用前你需要知道,ids参数应该是一个字符串列表,必须和数据对象列表的长度保持一致,我们可以试着使用ids,看下效果

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data_1 = [
  15. (1, 2, 3),
  16. (4, 5, 9)
  17. ]
  18.  
  19. ids = ["a:{} + b:{} = expect:{}".format(a, b, expect) for a, b, expect in data_1]
  20.  
  21. def add(a, b):
  22. return a + b
  23.  
  24. @pytest.mark.parametrize('a, b, expect', data_1, ids=ids)
  25. class TestParametrize(object):
  26.  
  27. def test_parametrize_1(self, a, b, expect):
  28. print('\n测试函数1测试数据为\n{}-{}'.format(a, b))
  29. assert add(a, b) == expect
  30.  
  31. def test_parametrize_2(self, a, b, expect):
  32. print('\n测试函数2数据为\n{}-{}'.format(a, b))
  33. assert add(a, b) == expect
  34.  
  35. if __name__ == '__main__':
  36. pytest.main(['-v']) # -v : 更加详细的输出测试结果

输出

装饰器不传递ids参数的输出

  1. collecting ... collected 4 items
  2.  
  3. test_parametrize.py::TestParametrize::test_parametrize_1[1-2-3] PASSED [ 25%]
  4. test_parametrize.py::TestParametrize::test_parametrize_1[4-5-9] PASSED [ 50%]
  5. test_parametrize.py::TestParametrize::test_parametrize_2[1-2-3] PASSED [ 75%]
  6. test_parametrize.py::TestParametrize::test_parametrize_2[4-5-9] PASSED [100%]
  7.  
  8. ========================== 4 passed in 0.16 seconds ===========================
  9.  
  10. Process finished with exit code 0

装饰器传递ids参数的输出

  1. collecting ... collected 4 items
  2.  
  3. test_parametrize.py::TestParametrize::test_parametrize_1[a:1 + b:2 = expect:3] PASSED [ 25%]
  4. test_parametrize.py::TestParametrize::test_parametrize_1[a:4 + b:5 = expect:9] PASSED [ 50%]
  5. test_parametrize.py::TestParametrize::test_parametrize_2[a:1 + b:2 = expect:3] PASSED [ 75%]
  6. test_parametrize.py::TestParametrize::test_parametrize_2[a:4 + b:5 = expect:9] PASSED [100%]
  7.  
  8. ========================== 4 passed in 0.20 seconds ===========================
  9.  
  10. Process finished with exit code 0

说明

执行命令我使用了-v,会更加详细的显示输出结果,可以看到所有的数据结果中的用例都被一个列表明确的标记了,而且通过这种标记可以更加直观的看出来,每个测试用例使用的数据名称及测试内容

自定义id做标识

除了使用ids参数增加输出可读性外,我们还可以在参数列表的参数旁边定义一个id值来做标识,看下面实例

  1. """
  2. ------------------------------------
  3. @Time : 2019/7/25 19:18
  4. @Auth : linux超
  5. @File : test_parametrize.py
  6. @IDE : PyCharm
  7. @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
  8. @QQ : 28174043@qq.com
  9. @GROUP: 878565760
  10. ------------------------------------
  11. """
  12. import pytest
  13.  
  14. data_1 = [
  15. pytest.param(1, 2, 3, id="(a+b):pass"), # id的值可以自定义, 只要方便理解每个用例是干什么的即可
  16. pytest.param(4, 5, 10, id="(a+b):fail")
  17. ]
  18.  
  19. def add(a, b):
  20. return a + b
  21.  
  22. class TestParametrize(object):
  23.  
  24. @pytest.mark.parametrize('a, b, expect', data_1)
  25. def test_parametrize_1(self, a, b, expect):
  26. assert add(a, b) == expect
  27.  
  28. if __name__ == '__main__':
  29. pytest.main(['-v'])

输出

  1. test_parametrize.py::TestParametrize::test_parametrize_1[(a+b):pass] PASSED [ 50%]
  2. test_parametrize.py::TestParametrize::test_parametrize_1[(a+b):fail] FAILED [100%]
  3.  
  4. ================================== FAILURES ===================================
  5. _______________ TestParametrize.test_parametrize_1[(a+b):fail] ________________
  6.  
  7. self = <pytest_parametrize.test_parametrize.TestParametrize object at 0x000001D7BFC4C748>
  8. a = 4, b = 5, expect = 10
  9.  
  10. @pytest.mark.parametrize('a, b, expect', data_1)
  11. def test_parametrize_1(self, a, b, expect):
  12. > assert add(a, b) == expect
  13. E assert 9 == 10
  14. E -9
  15. E +10
  16.  
  17. test_parametrize.py:28: AssertionError
  18. ===================== 1 failed, 1 passed in 0.35 seconds ======================
  19.  
  20. Process finished with exit code 0

说明

如果使用此方法来标记测试用例,一定要严格按照我写的格式来使用,语法为pytest.param(value, id='somthing')

总结

Pytest中实现数据驱动就是如此了

掌握

1.装饰器与测试用例使用单个变量接收多组数据与多个变量接收多个数据的访问方法

2.不同测试数据形式(列表嵌套元组,列表,字典等)时,如何传递数据及访问数据

3.装饰器装饰测试类和测试函数的不同之处:装饰测试类时,类内所有的方法必须接送测试数据,否则会报错,装饰测试函数时比较灵活,如果函数不使用数据就可以不装饰

4.为了输出结果的可读性,可以选择使用ids参数,与测试数据中定义id参数值来标识测试用例

注意

1. 装饰器的第一个参数是一个列表形式的字符串参数"a, b, c" 不能写成"a", "b", "c"

2. ids是个字符串列表,它的长度需要与测试数据列表的长度一致

Pytest进阶之参数化的更多相关文章

  1. 11、pytest -- 测试的参数化

    目录 1. @pytest.mark.parametrize标记 1.1. empty_parameter_set_mark选项 1.2. 多个标记组合 1.3. 标记测试模块 2. pytest_g ...

  2. pytest -- 测试的参数化

    目录 1. @pytest.mark.parametrize标记 1.1. empty_parameter_set_mark选项 1.2. 多个标记组合 1.3. 标记测试模块 2. pytest_g ...

  3. Pytest进阶使用

    fixture 特点: 命令灵活:对于setup,teardown可以省略 数据共享:在conftest.py配置里写方法可以实现数据共享,不需要import导入,可以跨文件共享 scope的层次及神 ...

  4. pytest进阶之配置文件

    前言 pytest配置文件能够改变pytest框架代码的运行规则.比如修改pytest收集用例的规则,添加命令行参数等等!下面我们来一一讲解常用的一些配置项 Help 通过命令pytest --hel ...

  5. pytest进阶之html测试报告

    前言 Pytest系列已经写了几篇文章了,也不知道对多少人有帮助,总之对于我自己来说该掌握的都已经掌握了,那么今天我们再来说说pytest如何生成一个完整的html测试报告,让你在吹牛逼的路上再多一份 ...

  6. pytest进阶之xunit fixture

    前言 今天我们再说一下pytest框架和unittest框架相同的fixture的使用, 了解unittest的同学应该知道我们在初始化环境和销毁工作时,unittest使用的是setUp,tearD ...

  7. pytest进阶之conftest.py

    前言 前面几篇随笔基本上已经了解了pytest 命令使用,收集用例,finxture使用及作用范围,今天简单介绍一下conftest.py文件的作用和实际项目中如是使用此文件! 实例场景 首先们思考这 ...

  8. pytest进阶之fixture

    前言 学pytest就不得不说fixture,fixture是pytest的精髓所在,就像unittest中的setup和teardown一样,如果不学fixture那么使用pytest和使用unit ...

  9. pytest进阶

    参考文章 使用 pytest pytest 这个 库是一个第三方库,严格来说,它的设计思路不属于 xUnit 系列.但它使用起来比较方便,同时他又兼容 unittest 的用例:用 unittest ...

随机推荐

  1. vs2010添加TSTCON( ActiveX Control Test Container )工具

    vs2010中的TSTCON( ActiveX Control Test Container )工具非自动安装,而是作为一个例程提供.所以应找到该例程,并编译: 如vs2010安装在默认路径则 1, ...

  2. ViewPager页面滑动,滑动到最后一页,再往后滑动则执行一个事件

    1.ViewPager在处理滑动事件的时候要用到OnPageChangeListener( 代码:this.viewPager.setOnPageChangeListener(new MyListen ...

  3. 304902阿里巴巴Java开发手册1.4.0

    转自官网 前言 <阿里巴巴Java开发手册>是阿里巴巴集团技术团队的集体智慧结晶和经验总结,经历了多次大规模一线实战的检验及不断完善,系统化地整理成册,回馈给广大开发者.现代软件行业的高速 ...

  4. Linux下python多版本多环境介绍

     一.python多版本配置说明 安装python相关依赖 [root@centos6 ~]# yum install -y gcc make patch gdbm-devel openssl-dev ...

  5. 进程以及进程通信(IPC)类型

    这里用我有限的知识来解释同时参考了一些其他博主的子类,希望能给与一部分入门的朋友一个清晰的理解,有问题之处还请指出 首先简单谈一下什么是进程? 答:进程是装入内存运行的程序段,是许多的系统对象拥有权的 ...

  6. Django的的安装和配置

    1. 下载 1. 命令行 pip install django==1.11.18 -i https://pypi.douban.com/simple/ 2. 创建项目 1. 命令行 django-ad ...

  7. SpringBoot从入门到精通十一(SpringBoot文件上传的两种方法)

    前言 在企业级项目开发过程中,上传文件是最常用到的功能.SpringBoot集成了SpringMVC,当然上传文件的方式跟SpringMVC没有什么出入. 本章目标 使用SpringBoot项目完成单 ...

  8. Fabric1.4源码解析:客户端创建通道过程

    在使用Fabric创建通道的时候,通常我们执行一条命令完成,这篇文章就解析一下执行这条命令后Fabric源码中执行的流程. peer channel create -o orderer.example ...

  9. Storm 学习之路(六)—— Storm项目三种打包方式对比分析

    一.简介 在将Storm Topology提交到服务器集群运行时,需要先将项目进行打包.本文主要对比分析各种打包方式,并将打包过程中需要注意的事项进行说明.主要打包方式有以下三种: 第一种:不加任何插 ...

  10. Nagios安装配置教程(一)基本了解

    一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态, 交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信 ...