全网最详细的Python自动化测试(unittest框架)

 🔥 交流讨论:欢迎加入我们一起学习!

🔥 资源分享耗时200+小时精选的「软件测试」资料包

🔥 教程推荐:火遍全网的《软件测试》教程  

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

一、什么是框架

框架是由大佬开发或者专业的研发团队研发的技术骨架,框架是一个半成品,框架是对常用的功能,基础的代码进行封装的一个工具,这个工具对外提供了一些API,其他的开发者只需要调用框架的接口即可,可以省去很多代码的编写,从而提高工作效率。

二、什么是自动化工具

1、自动化框架

自动化测试大佬(测试领导等)对系统做自动化测试而封装的测试框架,其他的自动化测试工程师去调用自动化测试框架完成测试工作,简单来说,自动化框架就是大佬封装的一个对系统进行自动化测试的工具而已,测试人员只需要学会使用这个工具对系统进行测试即可。

2、自动化测试框架的作用

2.1 提高测试效率,降低维护成本
2.2 提高代码的复用性
2.3 减少人工的干预

3、unittest单元测试框架和自动化测试框架的关系

3.1 单元测试

单元测试主要是针对程序的最小单元进行测试,最小单元一般指的是程序的方法。

备注:在python中,为了细致性的区分方法和函数,将类以外的定义的方法叫做函数,类里面的方法叫做方法

3.2 自动化测试框架有哪些

自动化框架主要有:unittest(单元测试工具)、pom、ddt(数据驱动工具)、全局配置文件工具、selenium二次封装、assert(断言)、邮件发送等。简单来说,自动化测试框架包含了所有的测试工作所需的测试框架。

三、Python中pytest和unittest的对比

基于python的单元测试框架:unittest和pytest

基于java的单元测试框架:junit和testng

1、用例编写规则

1.1 unittest

unittest提供了TestCases测试用例类、testsuits测试套件、testfixtures测试夹具、testLoader测试类加载器、testrunner测试运行器、但是必须遵循以下的规则:

(1)测试文件必须先导入unittest包:import unittest

(2)测试类必须继承unittest.TestCase

(3)测试方法必须以test开头

1.2 pytest

pytest是基于python的第三测试框架,基于unittest的扩展框架,必须遵循以下的规则:

(1)测试文件名必须以test_开头或者___test结尾

(2)测试类的命名必须以Test开头

(3)测试方法必须以test_开头

2、测试用例的前置和后置

2.1 unittest


2.2 pytest


备注:还可以在函数之前加@pytest.fixture()实现以上的这些方法;pytest中将类中定义的方法叫做方法,在类之外叫做函数。

3、断言

3.1 unittest

  • assertTrue(a):判断a是否为真
  • assertEqual(a,b):判断a和b是否一致
  • assertIn(a,b):判断a是否在b里面
  • assertNotEqual(a,b):判断a!=b
  • assertNotIn(a,b):判断a是否在b里面
  • assertFalse(a):判断a是否为假

3.2 pytest
原生的assert

4、 测试报告

4.1 unittes
htmlesrunner:导包,下载py3支持包,导入即可使用

4.2 pytes
pytest-HTML、allure插件

5、失败重跑

5.1 unittest
没有

5.2 pytest
pytest-returnfailures插件

6、数据驱动

6.1 unittest
@ddt

6.2 pytest
@pytest.mark.parametrize装饰器

7、 用例分类执行

7.1 unittest
默认执行所有,也可以通过通过testsuite来执行部分用例,或者使用-k参数来执行

7.2 pytest
@pytest.mark

四、unittest框架主要工作

1、测试发现
从多个文件中收集并加载测试执行用例

2、测试执行
将测试用例按照一定的顺序和条件去执行

3、测试判断
用断言去判断测试用例的执行结果(实际结果)与预期结果是否一致

4、测试报告
统计测试测试进度,通过个数,失败个数等,形成测试报告

五、unittest中重要插件

1、TestCase
2、TestSuite
3、TestFixture
4、TestLoader
5、TestRunner

六、组件的使用(重点)

1、命名规范

1.1 模块的命名规范

项目名称_功能模块名称,例如:epr管理系统下的登录模块—>erp__login.py(python中一个py文件就可以看作一个模块)

1.2 类的命名规范

项目名称(首字母大写)_功能模块名称(首字母大写)。例如:epr管理系统下的登录模块类—>class Erp__Login(其中class是声明一个类)

1.3 测试方法的命名

严格遵顼test0x_功能模块名称(或者测试点)点方式来命名,因为unittest底层采用ASCII来匹配方法,如果不按照这种方式来命名,对于测试方法的执行顺序不好控制,以这样的方式来命名的话,严格按照0x的大小顺序执行测试方法。

案例1:按照test1、test2、test11、test12的顺序执行测试方法

 
  1. # 2、命名规

  2. # (1)导包

  3. # (2)继承TestCase

  4. # 测试方法的执行应该按照:test1->test2->test11->test12的顺序执行

  5. import unittest

  6. class NameRule(unittest.TestCase):

  7. def test1(self):

  8. print('test1')

  9. def test2(self):

  10. print('test2')

  11. def test11(self):

  12. print('test11')

  13. def test12(self):

  14. print('test12')

  15. #结果:与预期的执行顺序不一致

  16. #Process finished with exit code 0

  17. #test1

  18. #test11

  19. #test12

  20. #test2

结果截图:

案例2:按照test1、test2、test11、test12的顺序执行测试方法

 
  1. # 2、命名规

  2. # (1)导包

  3. # (2)继承TestCase

  4. import unittest

  5. class NameRule1(unittest.TestCase):

  6. def test01(self):

  7. print('test1')

  8. def test02(self):

  9. print('test2')

  10. def test11(self):

  11. print('test11')

  12. def test12(self):

  13. print('test12')

结果截图:

2、unittest.TestCase类的使用

新建的测试用例类继承TestCase类,这样需要进行测试的测试用类就可以使用TestCase的方法了。案例:erp关系系统登录和新增用户的两个模块的测试

 
  1. # 1、TestCase的用法

  2. # (1)导包

  3. # (2)继承

  4. import unittest

  5. class ErpLogin(unittest.TestCase):#光标点击到这里,右键,点击run,执行下面的全部方法,也就是执行全部测试用例

  6. def test01_login(self):# 光变点击到这里,右键,点击run,执行test01_login这个方法

  7. print('erp管理系统的login(登录)测试')

  8. def test02_loginCheckParam(self):

  9. print('erp管理系统login登录参数验证测试')

  10. def test03_addUser(self):

  11. print('erp管理系统addUser新增用户测试')

2.1 测试用例的执行方式

测试用例的执行方法主要有两种,在pycharm中执行和在命令行中执行

2.2.1 在pycharm中执行

第一种方式:点击类左边的执行按钮或者将光标移动到类的左边,点击右键,点击run,执行类中全部的测试方法

备注:这种方式本质上就是“运行一个类”,包括这个类中的所有方法

第二种运行方式:点击类中的某个方法的左边的执行按钮或者将光标移动到某个方法的左边,点击右键,点击run则执行的是该测试类的某个具体的方法。

备注:这中运行方式的本质上就是运行测试类中指定的某个方法。

第三种运行方式:配置pycharm全局配置和临时配置,这种方式是运行测试类的全部测试方法

(1)临时配置:临时配置某个测试类的运行方式

第一步:配置运行

第二步:配置python test中的unittest

第三步:配置需要测试的脚本

第四步:配置好测试脚本之后,点击apply和ok即可

(2)全部配置(查询资料即可),这里不在叙述

2.2.2 命令行的方式执行测试方法

(1)命令行的发现:使用python -m unittest 的命令来执行测试方法(Launching unittests with arguments python -m unittest name_rule1.NameRule1 in D:\pyhton-product\pythonbase\nnittest_stu**–>**使用D:\pyhton product\pythonbase\nnittest_stu中的参数python-m unittest name_rule1.NameRule1启动unittest)

第一步:右键,打开命令行终端

第二步:输入指令python -m unittest name_rule.NameRule1即可

备注:命令行的方式本质上是使用python指令来运行python程序,可以通过python --help查看指令用法

(1)比如我想通过python指令的方式只允许NameRule1中的test01方法

 
  1. #python --help

  2. python -m unittest name_rule1.NameRule1.test01

(2)通过python指令运行NameRule1中的test01和test02方法,并打印详细信息

 
  1. # -v 表示详细打印处运行结果

  2. # -m 表示将py程序作为一个脚本来执行

  3. # -k 表示匹配模式,用于直想运行测试类中的某些方法(两种匹配方式)

  4. python -m unittest name_rule1.NameRule1.test01 name_rule1.NameRule1.test02 -v


(3)几个重要参数(-m,-v,-k)

备注:统配符主要是继承Jenkins的时候用,为什么?所有的命令行的方式都是加非GUI的方式。postman:非GUI newman;Jmeter jmeter指令

(4)执行类似test的所有方法,并打印出详细运行信息

python -m unittest name_rule1.NameRule1 -k * -v 

通配符:-k *_的方式进行匹配

字符串:-k 字符串(根据字符串进行模糊匹配),在类中顺序逐个寻找包含含字符串的方法名test01 例如,test01可以通过0、1、tst、tst01等字符串找到,但是不能通过10tset的方式找到,也就是倒序方式不能找到

2.2.3 使用unittest.main的方式运行

以模块的方式运行。在pycharm中配置main运行方式

注意:点击main左边的运行按钮运行不是main运行,是命令行的方式

配置pyhton的main运行

2.2 pycharm和命令行的联系

我个人的理解是这样的,pycharm中配置运行本质上就是调用python指令来完成的,在python中,有一个程序为python.exe,这个程序可以让我们使用python指令来运行我们py文件,因此pycharm只是将命令行的运行方式变成了界面运行,方便我们操作。main的运行方式是指就是通过python 模块名.py来完成的。

2.3 执行结果

  • . 执行成功
  • F 执行失败
  • S 跳过:@unittest.skip()用在测试方法上,跳过不执行
  • E 错误
 
  1. # 2、命名规

  2. # (1)导包

  3. # (2)继承TestCase

  4. import unittest

  5. class NameRule1(unittest.TestCase):

  6. # 执行成功

  7. def test01(self):

  8. print('test1')

  9. # 执行错误

  10. def test02(self):

  11. print('test2')

  12. raise Exception("执行错误")

  13. # 执行跳过

  14. @unittest.skip('跳过')

  15. def test11(self):

  16. print('test11')

  17. # 执行失败

  18. def test12(self):

  19. self.assertTrue(0)#0不为True

  20. print('test12')

  21. if __name__ == '__main__':

  22. print('=============main================')

  23. unittest.main()

2.4 测试方法的执行顺序(没有深入研究,记住命名规范即可)

按照ASCII的方式执行测试方法,test01一定在test02之前运行。ASCII码按照testxx的方式进行读取测试方法,按照读取到的第一个字母的ASCII码的大小进行执行,如果ASCII码的值越小,ASCII小的优先执行。ASCII码规则:【0-9 A-Z a-z】A=65 a=97

 
  1. # 2、命名规

  2. # (1)导包

  3. # (2)继承TestCase

  4. import unittest

  5. class NameRule(unittest.TestCase):

  6. def testa(self):

  7. print('testa')

  8. def testb(self):

  9. print('testb')

  10. def test11(self):

  11. print('test11')

  12. def test12(self):

  13. print('test12')

  14. def test01(self):

  15. print('test01')

  16. def test02(self):

  17. print('test02')

  18. def test01_a(self):

  19. print('test01_a')

  20. def test02_b(self):

  21. print('test02_b')

  22. def t1(self):#没有按照命名规范进行命名,不执行

  23. print('t1')

  24. def t2(self):

  25. print('t2')

  26. if __name__ == '__main__':

  27. print('测试方法执行顺序')

  28. unittest.main()

执行结果

2.5unittest中main方法解析

参数解析(加粗的表示比较重要的几个参数)

3、TestSuite的使用

3.1 TestSuite的作用

在unittest提供了TestSuite(测试套件)类,测试套件的主要功能是实现测试类里面需要执行测试方法,在测试套件中制定好了需要进行的测试方法,即可完成测试类中指定测试方法的执行,比如,在erp管理系统中,只完成登录模块参数检验和登录验证的测试。

 
  1. # 1、TestCase的用法

  2. # (1)导包

  3. # (2)继承

  4. import unittest

  5. class ErpLogin1(unittest.TestCase):

  6. def test01_login(self):

  7. print('erp管理系统的login(登录)测试')

  8. def test02_loginCheckParam(self):

  9. print('erp管理系统login登录参数验证测试')

  10. def test03_addUser(self):

  11. print('erp管理系统addUser新增用户测试')

  12. if __name__ == '__main__':

  13. print('==========erp管理系统登录模块的验证===================')

  14. # 只完成登录参数校验的验证测试和登录的测试

  15. # 第一种方法,在main方法中指定需要测试测试方法

  16. # unittest.main(defaultTest=['ErpLogin1.test02_loginCheckParam','ErpLogin1.test01_login'])

  17. # 第二种方法 采用测试套件TestSuite

  18. # testSuite = unittest.TestSuite()

  19. # 添加需要测试的测试方法

  20. # testSuite.addTest(test=ErpLogin1('test02_loginCheckParam'))#本质上就是testsuite来实现的

  21. # testSuite.addTest(ErpLogin1('test01_login'))#这里使用的是方法名

  22. # 这里也可以使用addTests()参数是可迭代对象,其实就是列表

  23. # testSuite.addTests([ErpLogin1('test02_loginCheckParam'), ErpLogin1('test01_login')])

  24. # 执行测试方法,将测试的结果使用文本的方式打印出来

  25. # unittest.TextTestRunner().run(testSuite)

  26. # 第三种方法,通过类加载器的方式来实现

  27. # 获取测试套件

  28. suite = unittest.TestSuite()

  29. # 发现测试方法,并加载测试方法

  30. testMotheds = unittest.defaultTestLoader.discover(start_dir=r'D:\pyhton-product\pythonbase\nnittest_stu',pattern='*_login1.py')

  31. # 添加需要测试的方法

  32. suite.addTests(testMotheds)

  33. # 执行测试

  34. unittest.main()

3.2 TestSuite常用方法

  • addTest():添加一个测试方法,传递的参数是一个测试对象即可,例如ErpLogin1(‘test01_login’)
  • addTests():添加多个测试方法,传递的参数是测试对象的列表,例如[ErpLogin1(‘test02_loginCheckParam’), ErpLogin1(‘test01_login’)]

3.3 TestSuite的运行

testTuite的本质就是作为unittest.TextTestRunner().run()的参数,unittest.TextTestRunner().run()对测试方法进行测试,需要的是一个测试套件作为参数,而测试套件则确定了要执行哪些测试方法。

3.4 执行测试方法中常用的方式

3.4.1 通过main方法来传递参数(通解)

  • 其中比较重要的一个参数是defaultTest,指定需要加载测试方法有哪些,这样就可以实现一个或者多个方法的执行。

3.4.2 通过suite(测试套件)添加需要的测试方法(适用于一个测试类)

  • suite = unittest.TestSuite() :获取测试套件
  • suite.addTest()/suite.addTests(testObject):添加待测试方法对象,例如:ErpLogin1(‘test01_login’)(实例化了一个测试对象)
  • unittest.TextTestRunner.run(suite):执行测试方法

3.4.3 使用默认类加载器的方式来加载并执行测试方法(适用于多个测试类)

  • suite=unittest.testSuite():获取测试套件
  • testMethods = unittest.defaultLoader.discover(start_dir,parten):发现测试方法(目录+模式,可以加载多个测试文件Test.py)*
  • suite.addTests(testMethods):添加测试对象,原理和suite.addTest()一样
  • unittest.main():执行测试方法

4、TestFixTure的使用(setxxx的方法一般被叫做夹具)

4.1 setUp()和tearDown()的使用(在每个方法之前或者之后执行一次)

  • 适用场景:一般用于打开浏览器和关闭浏览器,简单来说就就是进行测试方法执行的时候,前置条件是什么,做完之后还要做哪些收尾工作。
  • 导包:import unittest
  • 继承:继承TestCase类
  • 重写setUp和tearDown方法
  • 运行测试方法:unittest.main(defaultTest=[])

案例:

 
  1. import unittest

  2. # 需求:在测试登录功能之前,必须先要打开浏览器,加载浏览器,关闭浏览器

  3. # 打开浏览器和关闭浏览器是每一次登录之前就要做的事,因此在进行登录测试之前,

  4. # 先打开浏览器,然后登录测试,关闭浏览器

  5. class TestLogin(unittest.TestCase):

  6. def setUp(self) -> None:

  7. print('打开浏览器,加载浏览器')

  8. def tearDown(self) -> None:

  9. print('关闭浏览器')

  10. def test01_login(self):

  11. print('test01_login')

  12. def test02_login2(self):

  13. print('test02_login2')

  14. if __name__ == '__main__':

  15. print('==============main=================')

  16. unittest.main(defaultTest=['TestLogin.test01_login', 'TestLogin.test02_login2'])

结果:

 
  1. ==============main=================

  2. 打开浏览器,加载浏览器

  3. test01_login

  4. 关闭浏览器

  5. 打开浏览器,加载浏览器

  6. test02_login2

  7. 关闭浏览器

  8. ..

  9. ----------------------------------------------------------------------

  10. Ran 2 tests in 0.000s

4.2 setUpClass()和tearnDownClass()使用(在测试类之前或者之后执行一次)

  • 适用场景:一般用于连接数据库和关闭数据库连接以及一些日志对象的销毁
  • 导包:import unittest 和 需要导入的数据库连接类
  • 继承:继承TestCase类
  • 重写setUpClass和tearDownClass方法,必须在方法前加装饰器@classmethod
  • 运行测试方法:unittest.main(defaultTest=[])

案例:

 
  1. # database.py

  2. class DataBase():

  3. def link(self):

  4. print('连接数据库')

  5. def close(self):

  6. print('关闭数据库')

 
  1. import unittest

  2. # 导入数据库连接类所在的包(自定义)

  3. import database

  4. # 需求:在测试登录功能之前,必须先要打开浏览器,加载浏览器,关闭浏览器

  5. # 打开浏览器和关闭浏览器是每一次登录之前就要做的事,因此在进行登录测试之前,

  6. # 先打开浏览器,然后登录测试,关闭浏览器

  7. class TestLogin(unittest.TestCase):

  8. @classmethod

  9. def setUpClass(cls) -> None:

  10. db = database.DataBase()

  11. db.link()

  12. @classmethod

  13. def tearDownClass(cls) -> None:

  14. database.DataBase().close()

  15. def setUp(self) -> None:

  16. print('打开浏览器,加载浏览器')

  17. def tearDown(self) -> None:

  18. print('关闭浏览器')

  19. def test01_login(self):

  20. print('test01_login')

  21. def test02_login2(self):

  22. print('test02_login2')

  23. if __name__ == '__main__':

  24. print('==============main=================')

  25. unittest.main(defaultTest=['TestLogin.test01_login', 'TestLogin.test02_login2'])

结果:

 
  1. ==============main=================

  2. 连接数据库

  3. 打开浏览器,加载浏览器

  4. test01_login

  5. 关闭浏览器

  6. 打开浏览器,加载浏览器

  7. test02_login2

  8. 关闭浏览器

  9. 关闭数据库

  10. ..

  11. ----------------------------------------------------------------------

  12. Ran 2 tests in 0.000s

4.3 setUpModule()和tearDownModule()的使用(函数级别的,在模块之前或者之后执行一次)

在python中,所谓的模块指的就是一个py文件。setUpModule和setDownModule都是定义在木块中的函数,这个做个演示即可,使用的场景不是很多。因为测试用例一般是独立的,不可以相互关联。

案例:

 
  1. # database.py

  2. class DataBase():

  3. def link(self):

  4. print('连接数据库')

  5. def close(self):

  6. print('关闭数据库')

 
  1. import unittest

  2. import database

  3. # 需求:在测试登录功能之前,必须先要打开浏览器,加载浏览器,关闭浏览器

  4. # 打开浏览器和关闭浏览器是每一次登录之前就要做的事,因此在进行登录测试之前,

  5. # 先打开浏览器,然后登录测试,关闭浏览器

  6. def setUpModule():

  7. print('setUpAndtearDown.py模块之前')

  8. def tearDownModule():

  9. print('setUpAndtearDown.py模块之后')

  10. class TestLogin(unittest.TestCase):

  11. @classmethod

  12. def setUpClass(cls) -> None:

  13. db = database.DataBase()

  14. db.link()

  15. @classmethod

  16. def tearDownClass(cls) -> None:

  17. database.DataBase().close()

  18. def setUp(self) -> None:

  19. print('打开浏览器,加载浏览器')

  20. def tearDown(self) -> None:

  21. print('关闭浏览器')

  22. def test01_login(self):

  23. print('test01_login')

  24. def test02_login2(self):

  25. print('test02_login2')

  26. if __name__ == '__main__':

  27. print('==============main=================')

  28. unittest.main(defaultTest=['TestLogin.test01_login', 'TestLogin.test02_login2'])

结果:

 
  1. ==============main=================

  2. ..

  3. ----------------------------------------------------------------------

  4. Ran 2 tests in 0.000s

  5. OK

  6. setUpAndtearDown.py模块之前

  7. 连接数据库

  8. 打开浏览器,加载浏览器

  9. test01_login

  10. 关闭浏览器

  11. 打开浏览器,加载浏览器

  12. test02_login2

  13. 关闭浏览器

  14. 关闭数据库

  15. setUpAndtearDown.py模块之后

  16. Process finished with exit code 0

4.4 忽略测试用例

在执行一些测试用例的时候,我们可能会对一些测试用例进行忽略,不需要进行测试,在unittest中有两种忽略方式:无条件忽略和有条件忽略。

  • @unittest.skip(des):参数为忽略的原因
  • @unitest.skipIf():两个参数,第一个参数是忽略的条件,为真就忽略;第二个为什么忽略的描述。
  • @unittest.skipUnless():和@unitest.skipIf()一样,只不过是为假的时候才会忽略。

备注:@unittest.skip(des)放在方法之前,表示测试方法跳过,忽略;@unittest.skip(des)放在模块上面,直接跳过整个模块

七、数据驱动

1、为什么要有数据驱动

在软件测试中,测试用例的数据往往都是写在excel表格中,而不是我们去拿着软件边想边测试,因此在进行测试用例的时候,我们需要将测试数据(测试用例)从excel中读取出来,然后让测试方法去执行我们写的测试用例。

2、驱动模式介绍

  • 数据驱动
  • 关键字驱动:将核心业务逻辑封装成方法,然后直接调用方法
  • 混合驱动模式:关键字+数据驱动——》市场主流
  • 行为测试驱动:Lettuce

3、DDT

  • DDT定义:data driver test,数据驱动测试点。特点:可以完美的和unittest结合使用,通过数据驱动,将我们写的测试用例读取出来,然后执行测试用例。
  • DDT的使用:通过装饰器的形式来调用。
  • 装饰器:完成某种特定功能的函数(就是java中的注解)
  • 在python中的定义:以@开头,装饰器主要有两种,一种是类装饰器,另一种是函数装饰器。

4、DDT中的装饰器(重点)

  • @ddt():类装饰器,声明当前类是ddt的框架
  • @data():函数装饰器,用于给测试方法传递数据,其中*表示格式化传递的数据,如果传递的是列表(字典,元组)的嵌套,就会把列表(字典,元组)进行格式化
  • @unpack():函数装饰器,将传输的数据进行解包,一般作用于元组tuple和列表list
  • @file_data():函数装饰器,可以直接读取json和ymal文件

5、@data的使用

传值类型:@data可以传递的数据类型有:数字(float、int、bigint、double、compix)、字符串string、列表list、元组tuple、集合set

 
  1. import unittest

  2. from ddt import ddt, data

  3. @ddt # 类装饰器,表示要使用ddt框架

  4. class DataSend(unittest.TestCase):

  5. # 传递数字

  6. @data(10)

  7. def test01_data_send_int(self, param1):

  8. print(param1)

  9. # 传递字符串

  10. @data('string')

  11. def test02_data_send_string(self, param1):

  12. print(param1)

  13. # 传递元组

  14. @data((1, 2, 3))

  15. def test03_data_send_tuple(self, param1):

  16. print(param1)

  17. # 传递列表

  18. @data([4, 5, 6, 7])

  19. def test04_data_send_list(self, param1):

  20. print(param1)

  21. # 传递字典

  22. @data({'name': 'bugchen', 'age': 18})

  23. def test05_data_send_dict(self, param1):

  24. print(param1)

  25. if __name__ == '__main__':

  26. unittest.main()

  27. # 结果:

  28. # 10

  29. # string

  30. # (1, 2, 3)

  31. # [4, 5, 6, 7]

  32. # {'name': 'bugchen', 'age': 18}

传值个数:@data传值的个数为一个的时候,测试方法执行一次,传递多个值的时候,就执行多次,总的来说,传递几个值,测试方法就会执行几次

 
  1. import unittest

  2. from ddt import ddt, data

  3. @ddt

  4. class DataNums(unittest.TestCase):

  5. @data(12)

  6. def test01_one(self, param1):

  7. print(param1)

  8. @data(1, 2)

  9. def test02_two(self, param1):

  10. print(param1)

  11. @data(['a'])

  12. def test03_three(self, param1):

  13. print(param1)

  14. @data(['b'], ['b', 'c'])

  15. def test04_four(self, param1):

  16. print(param1)

  17. if __name__ == '__main__':

  18. unittest.main()

  19. # 结果

  20. # 12

  21. # 1

  22. # 2

  23. # ['a']

  24. # ['b']

  25. # ['b', 'c']

6、@unpack的使用

从上面我们可以看出,虽然传递多个参数的时候,我们可以执行多次,但是当我们在测试方法中接收数据的时候,只能接收一种数据类型的参数,对于列表,元组这样的数据类型我们该怎么接收呢?总不能接收之后在处理吧!因此@unpack就是用来解包的,对于元组和类型,列表类型的参数,它可以解析成多个单个值,比如(1,2,3)解析之后就是1,2,3三个值,这个时候,测试方法需要三个参数来进行接收;[‘1’,‘2’,‘3’]经过解析之后就是1,2,3三个字符串,这个时候也需要三个参数进行接收,不然会报错,参数个数必须一一对应。

 
  1. import unittest

  2. from ddt import ddt, data, unpack

  3. @ddt

  4. class DataNums(unittest.TestCase):

  5. @data([1, 2, 3]) # 数据类型是列表

  6. @unpack # 解包 1,2 ,3需要三个参数接收

  7. def test05(self,p1,p2,p3):#参数于解包后的参数个数对应

  8. print(p1)

  9. print(p2)

  10. print(p3)

  11. if __name__ == '__main__':

  12. unittest.main()

  13. # 结果

  14. # 1

  15. # 2

  16. # 3

备注:使用@unpack需要注意

  • 集合不能解包
  • 如果是数字或者字符串不需要解包
  • 列表可以解包
  • 元组可以解包
  • 字典可以解包,但是测试方法接收的值必须于字典的键一致
 
  1. import unittest

  2. from ddt import ddt, data, unpack

  3. @ddt

  4. class DataNums(unittest.TestCase):

  5. @data({'name': 'bugchen', 'age': 18}, {'name': 'chen', 'age': 28})

  6. @unpack # 因为字典中有两个键,因此参数需要用两个键来接收,并别键的名称一致

  7. #def test06(self, p1, p2):#不一致,报错

  8. # print(p1)

  9. # print(p2)

  10. def test06(self,name,age):#一致,运行成功

  11. print(name)

  12. print(age)

  13. if __name__ == '__main__':

  14. unittest.main()

  15. # 结果

  16. # OK

  17. # bugchen

  18. # 18

  19. # chen

  20. # 28

八、unittest实战

需求规格说明书:随机输入三个正整数个数,判断是否构成三角形,以及构成的什么边的三角形。(暂且不考虑正整数的范围)

测试需求:如果不能构成三角行,输出“不能构成三角形”;如果输入非法,提示“非法输入”;普通三角形用1表示,等腰三角形用2表示,等边三角形用3表示。

实战要求:编写测试用例,形成测试用例表,并从测试用例表中读取测试用例,执行测试用例,形成测试报告。

1、测试思路

1.1 等价类划分

1.1.1随机输入三个正整数个数

划分为两个等价类:三个正整数(有效)、三个非正整数(无效)

  • 三个正整数: 1种
  • 其中一个非正整数:小数、字符、负数、0 4种

1.1.2 判断是否构成三角形,以及构成的什么边的三角形

划分为两个等价类:构成和不构成

构成:普通,等腰,等边 5种

不构成:任意两边之和小于等于第三边 6种

2、编写测试用例(TriangleTestCase.xlsx)(暂且只写一部分)

3、python自动化思路

导入测试模块——》读取测试用例(数据驱动)——》编写测试方法——》执行测试用例——》形成测试报告——》自动发送测试报告给组长或者经理(暂且不做)

测试部分的代码如下:

 
  1. # 测试模块,负责三角模块的测试

  2. # 导入unittest测试单元

  3. import xlrd

  4. from xlutils import copy # 在写入excel表的时候,需要先拷贝再写入

  5. import unittest

  6. # 导入数据驱动

  7. from ddt import ddt, data, unpack

  8. # 导入待测试的测试用例数据的模块

  9. from day9.data import TriangleData

  10. # 导入需要测试的模块

  11. from day9.function import triangle

  12. @ddt # 声明使用ddt框架

  13. class TestTriangle(unittest.TestCase):

  14. # 获取TriangleData模块下的TriangleData类,并通过TriangleData获取测试用例数据

  15. triangleData = TriangleData.TriangleData().triangleData

  16. # print(triangleData)

  17. @data(*triangleData) # 传入数据 *表示解析数据格式,解析成列表的格式

  18. @unpack # 解包的数据类型为:列表、元组、字典

  19. def test01_isTriangle(self, row, a, b, c, except_res):

  20. t = triangle.Triangle()

  21. # 执行测试用例,真实结果

  22. real_res = t.isTriangle(a, b, c)

  23. # 将执行的结果写入工作簿

  24. write_isTriangle_result(row, real_res, except_res)

  25. # 断言进行预期结果与真实结果的判断

  26. self.assertEqual(except_res, real_res) # 注意,先传入预期结果,在传入实际结果

  27. def write_isTriangle_result(row, real_res, except_res):

  28. # 将实际结果和预期结果

  29. is_pass = '否'

  30. if except_res == real_res:

  31. is_pass = '是'

  32. # 将处理的结果写入cal_test表中

  33. # 打开源文件,并保留源文件的数据格式

  34. wb = xlrd.open_workbook(filename=r'D:\pyhton-product\day9\testCases\TriangleTestCase.xlsx',

  35. encoding_override='utf-8')

  36. # 复制原始的工作簿

  37. c_wb = copy.copy(wb)

  38. # 获取工作表

  39. c_sheet = c_wb.get_sheet(0)

  40. # 写入数据

  41. c_sheet.write(row, 5, real_res)

  42. c_sheet.write(row, 6, is_pass)

  43. # 保存复制下来的表格

  44. c_wb.save(r'D:\pyhton-product\day9\testCases\TriangleTestCase.xlsx')

  45. # 这一部分用于执行测试用例和生成测试报告

  46. # if __name__ == '__main__':

  47. # unittest.main()

每个包的含义:

测试报告:

最后我邀请你进入我们的【软件测试学习交流群:785128166】, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路

作为一个软件测试的过来人,我想尽自己最大的努力,帮助每一个伙伴都能顺利找到工作。所以我整理了下面这份资源,现在免费分享给大家,有需要的小伙伴可以关注【公众号:程序员二黑】自提!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/607643.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Web 功能以及源码讲解

Web 功能以及语言讲解 培训、环境、资料、考证 公众号:Geek极安云科 网络安全群:624032112 网络系统管理群:223627079 网络建设与运维群:870959784 移动应用开发群:548238632 短视频制作群: 744125867极…

【6D位姿估计】FoundationPose 跑通demo 训练记录

前言 本文记录在FoundationPose中,跑通基于CAD模型为输入的demo,输出位姿信息,可视化结果。 然后分享NeRF物体重建部分的训练,以及RGBD图为输入的demo。 1、搭建环境 方案1:基于docker镜像(推荐&#xf…

电脑windows系统压缩解压软件-Bandizip

一、软件功能 Bandizip是一款功能强大的压缩和解压缩软件,具有快速拖放、高速压缩、多核心支持以及广泛的文件格式支持等特点。 Bandizip软件的功能主要包括: 1. 支持多种文件格式 Bandizip可以处理多种压缩文件格式,包括ZIP, 7Z, RAR, A…

Win10环境下yolov8快速配置与测试-详细

0.0 说明 参考黄家驹的Win10 环境下YOLO V8部署,遇到一些问题,并解决实现,记录如下: 斜线字体是原博客中的创作 0.1 参考链接 https://blog.csdn.net/m0_72734364/article/details/128865904 1 Windows10下yolov8 tensorrt模型加速部署 …

苍穹外卖Day06笔记

疯玩了一个月,效率好低,今天开始捡起来苍穹外卖~ 1. 为什么不需要单独引入HttpClient的dependency? 因为我们在sky-common的pom.xml中已经引入了aliyun-sdk-oss的依赖,而这个依赖低层就引入了httpclinet的依赖,根据依…

Centos7网络处理name or service not known

1、编辑->虚拟网络编辑器 2、查看本机的ip 3、 /etc/sysconfig/network-scripts/ 查看文件夹下面的 ifcfg-eth33 后面的33可能不一样 vi /etc/resolv.conf 编辑文件添加以下DNS nameserver 114.114.114.114 4、设置本机的网络 5、ping www.baidu.com 先重启…

linux调试

文章目录 1. 使用打印来调试1.1 重定向1.2 标准预定义宏1.3 日志代码 2. 内核异常2.1 内核打印2.1.1 打印级别2.1.2 跟踪异常2.1.3 动态打印2.1.4 RAM console 2.2 OOPS2.2.1 有源代码的情况2.2.2 没有源代码的情况 3 查看日志4 工具调试 1. 使用打印来调试 1.1 重定向 2>…

Django之创建Model以及后台管理

一,创建项目App python manage.py startapp App 二,在App.models.py中创建类,以下是示例 class UserModel(models.Model):uid models.AutoField(primary_keyTrue, auto_createdTrue)name models.CharField(max_length10, uniqueTrue, db…

【C++11新特性】lambda表达式和应用场景

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

Jenkins--自动化构建和部署SpringBoot项目

一、实现目标 通过在Jenkins中创建流水线任务&#xff0c;编写流水线脚本以实现自动化构建和部署SpringBoot项目。流水线脚本主要实现以下几个步骤&#xff1a; Preparation&#xff1a;从gitee上拉取远程仓库的SpringBoot项目代码。Build&#xff1a;使用Maven对拉取的代码进…

【2024全国青少年信息素养大赛初赛时间以及模拟题】

2024全国青少年信息素养大赛时间已经出来了 目录 全国青少年信息素养大赛智能算法挑战赛初中模拟卷 全国青少年信息素养大赛智能算法挑战赛初中模拟卷 1、比赛时间和考试内容&#xff1a; 算法创意实践挑战赛初中组于5月19日举行&#xff0c;检录时间为10:30-11:00&#xf…

男士内裤什么材质的好?五款材质舒适的男士内裤品牌

男士内裤目前已经有非常多的选择&#xff0c;三角/平角、传统面料/功能面料、设计版型等等都五花八门&#xff0c;所以不少男性朋友在挑选内裤时都觉得选择过多&#xff0c;另人难以选择&#xff0c;同时还担心选到一些质量不好的内裤&#xff0c;舒适性不仅差而且对健康有影响…

C语言洛谷题目分享(11)回文质数

目录 1.前言 2.题目&#xff1a;回文质数 1.题目描述 2.输入格式 3.输出格式 4.输入输出样例 5.题解 3.小结 1.前言 哈喽大家好&#xff0c;今儿继续为大家分享一道蛮有价值的一道题&#xff0c;希望大家多多支持喔~ 2.题目&#xff1a;回文质数 1.题目描述 因为 151 …

ESP8266-01s刷入固件报SP8266 Chip efuse check error esp_check_mac_and_efuse

一、遇到的问题 使用ESP8266 固件烧录工具flash_download_tools_v3.6.8 烧录固件报错&#xff1a; 二、解决方法 使用espressif推出发基于python的底层烧写工具&#xff1a;esptool 安装方法&#xff1a;详见https://docs.espressif.com/projects/esptool/en/latest/esp32/ …

【Linux】进程间通信方式之管道

&#x1f916;个人主页&#xff1a;晚风相伴-CSDN博客 &#x1f496;如果觉得内容对你有帮助的话&#xff0c;还请给博主一键三连&#xff08;点赞&#x1f49c;、收藏&#x1f9e1;、关注&#x1f49a;&#xff09;吧 &#x1f64f;如果内容有误的话&#xff0c;还望指出&…

最新:Lodash 严重安全漏洞背后你不得不知道的 JavaScript 知识

可能有信息敏感的同学已经了解到&#xff1a;Lodash 库爆出严重安全漏洞&#xff0c;波及 400万 项目。这个漏洞使得 lodash “连夜”发版以解决潜在问题&#xff0c;并强烈建议开发者升级版本。 我们在忙着“看热闹”或者“”升级版本”的同时&#xff0c;静下心来想&#xf…

人工智能|推荐系统——工业界的推荐系统之冷启动

UGC的物品冷启有哪些 ⼩红书上⽤户新发布的笔记。 B站上⽤户新上传的视频。 今⽇头条上作者新发布的⽂章。 为什么要特殊对待新笔记&#xff1f; 新笔记缺少与⽤户的交互&#xff0c;导致推荐的难度⼤、效果差。 扶持新发布、低曝光的笔记&#xff0c;可以增强作者发布意愿…

在Ubuntu安装RPM文件

Ubuntu软件源包含数千个deb软件包&#xff0c;可以从Ubuntu软件中心或使用apt命令行安装。 Deb是所有基于Debian的Linux发行版&#xff0c;例如包括Ubuntu&#xff0c;Linux mint等发行版使用的安装包格式。 如果某些软件在Ubuntu软件源中不可用&#xff0c;可以通过启用适当的…

NOIP,CSP-J,CSP-S——函数

一、函数概念 /*函数返回类型 函数名(参数){语句 } */ int add(int x,int y){return x+y; } 调用这个函数add int main(){int x,y,z;scanf("%d%d",&x,&y);z=add(x,y);printf("%d",z); } 二、变量作用域 main函数的z只作用于第二个for语句…

Day3 | Java基础 | 4常见类

Day3 | Java基础 | 4 常见类 基础版Object类equalshashCode&#xff08;散列码&#xff09;hashCode和equals clone方法String类 问题回答版Object类Object类的常见方法有哪些&#xff1f;和equals()的区别是什么&#xff1f;为什么要有hashCode&#xff1f;hashCode和equals的…
最新文章