Python自动化测试详解

Python自动化测试详解
点击文末小卡片免费获取软件测试全套资料资料在手涨薪更快一、什么是框架框架是由大佬开发或者专业的研发团队研发的技术骨架框架是一个半成品框架是对常用的功能基础的代码进行封装的一个工具这个工具对外提供了一些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和testng1、用例编写规则1.1 unittestunittest提供了TestCases测试用例类、testsuits测试套件、testfixtures测试夹具、testLoader测试类加载器、testrunner测试运行器、但是必须遵循以下的规则1测试文件必须先导入unittest包import unittest2测试类必须继承unittest.TestCase3测试方法必须以test开头1.2 pytestpytest是基于python的第三测试框架基于unittest的扩展框架必须遵循以下的规则1测试文件名必须以test_开头或者___test结尾2测试类的命名必须以Test开头3测试方法必须以test_开头2、测试用例的前置和后置2.1 unittest2.2 pytest备注还可以在函数之前加pytest.fixture()实现以上的这些方法;pytest中将类中定义的方法叫做方法在类之外叫做函数。3、断言3.1 unittestassertTrue(a)判断a是否为真assertEqual(a,b)判断a和b是否一致assertIn(a,b)判断a是否在b里面assertNotEqual(a,b)判断abassertNotIn(a,b)判断a是否在b里面assertFalse(a)判断a是否为假3.2 pytest原生的assert4、 测试报告4.1 unitteshtmlesrunner导包下载py3支持包导入即可使用4.2 pytespytest-HTML、allure插件5、失败重跑5.1 unittest没有5.2 pytestpytest-returnfailures插件6、数据驱动6.1 unittestddt6.2 pytestpytest.mark.parametrize装饰器7、 用例分类执行7.1 unittest默认执行所有也可以通过通过testsuite来执行部分用例或者使用-k参数来执行7.2 pytestpytest.mark四、unittest框架主要工作1、测试发现从多个文件中收集并加载测试执行用例2、测试执行将测试用例按照一定的顺序和条件去执行3、测试判断用断言去判断测试用例的执行结果实际结果与预期结果是否一致4、测试报告统计测试测试进度通过个数失败个数等形成测试报告五、unittest中重要插件1、TestCase2、TestSuite3、TestFixture4、TestLoader5、TestRunner六、组件的使用重点1、命名规范1.1 模块的命名规范项目名称_功能模块名称例如epr管理系统下的登录模块—erp__login.pypython中一个py文件就可以看作一个模块1.2 类的命名规范项目名称首字母大写_功能模块名称首字母大写。例如epr管理系统下的登录模块类—class Erp__Login其中class是声明一个类1.3 测试方法的命名严格遵顼test0x_功能模块名称(或者测试点)点方式来命名因为unittest底层采用ASCII来匹配方法如果不按照这种方式来命名对于测试方法的执行顺序不好控制以这样的方式来命名的话严格按照0x的大小顺序执行测试方法。案例1按照test1、test2、test11、test12的顺序执行测试方法# 2、命名规 # 1导包 # 2继承TestCase # 测试方法的执行应该按照test1-test2-test11-test12的顺序执行 import unittest class NameRule(unittest.TestCase): def test1(self): print(test1) def test2(self): print(test2) def test11(self): print(test11) def test12(self): print(test12) #结果与预期的执行顺序不一致 #Process finished with exit code 0 #test1 #test11 #test12 #test2结果截图案例2按照test1、test2、test11、test12的顺序执行测试方法# 2、命名规 # 1导包 # 2继承TestCase import unittest class NameRule1(unittest.TestCase): def test01(self): print(test1) def test02(self): print(test2) def test11(self): print(test11) def test12(self): print(test12)结果截图2、unittest.TestCase类的使用新建的测试用例类继承TestCase类这样需要进行测试的测试用类就可以使用TestCase的方法了。案例erp关系系统登录和新增用户的两个模块的测试# 1、TestCase的用法 # 1导包 # 2继承 import unittest class ErpLogin(unittest.TestCase):#光标点击到这里右键点击run执行下面的全部方法也就是执行全部测试用例 def test01_login(self):# 光变点击到这里右键点击run执行test01_login这个方法 print(erp管理系统的login登录测试) def test02_loginCheckParam(self): print(erp管理系统login登录参数验证测试) def test03_addUser(self): 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方法#python --help python -m unittest name_rule1.NameRule1.test012通过python指令运行NameRule1中的test01和test02方法并打印详细信息# -v 表示详细打印处运行结果 # -m 表示将py程序作为一个脚本来执行 # -k 表示匹配模式用于直想运行测试类中的某些方法两种匹配方式 python -m unittest name_rule1.NameRule1.test01 name_rule1.NameRule1.test02 -v3几个重要参数-m-v-k备注统配符主要是继承Jenkins的时候用为什么所有的命令行的方式都是加非GUI的方式。postman非GUI newmanJmeter 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 错误# 2、命名规 # 1导包 # 2继承TestCase import unittest class NameRule1(unittest.TestCase): # 执行成功 def test01(self): print(test1) # 执行错误 def test02(self): print(test2) raise Exception(执行错误) # 执行跳过 unittest.skip(跳过) def test11(self): print(test11) # 执行失败 def test12(self): self.assertTrue(0)#0不为True print(test12) if __name__ __main__: print(main) unittest.main()2.4 测试方法的执行顺序没有深入研究记住命名规范即可按照ASCII的方式执行测试方法test01一定在test02之前运行。ASCII码按照testxx的方式进行读取测试方法按照读取到的第一个字母的ASCII码的大小进行执行如果ASCII码的值越小ASCII小的优先执行。ASCII码规则【0-9 A-Z a-z】A65 a97# 2、命名规 # 1导包 # 2继承TestCase import unittest class NameRule(unittest.TestCase): def testa(self): print(testa) def testb(self): print(testb) def test11(self): print(test11) def test12(self): print(test12) def test01(self): print(test01) def test02(self): print(test02) def test01_a(self): print(test01_a) def test02_b(self): print(test02_b) def t1(self):#没有按照命名规范进行命名不执行 print(t1) def t2(self): print(t2) if __name__ __main__: print(测试方法执行顺序) unittest.main()执行结果2.5unittest中main方法解析参数解析加粗的表示比较重要的几个参数3、TestSuite的使用3.1 TestSuite的作用在unittest提供了TestSuite测试套件类测试套件的主要功能是实现测试类里面需要执行测试方法在测试套件中制定好了需要进行的测试方法即可完成测试类中指定测试方法的执行比如在erp管理系统中只完成登录模块参数检验和登录验证的测试。# 1、TestCase的用法 # 1导包 # 2继承 import unittest class ErpLogin1(unittest.TestCase): def test01_login(self): print(erp管理系统的login登录测试) def test02_loginCheckParam(self): print(erp管理系统login登录参数验证测试) def test03_addUser(self): print(erp管理系统addUser新增用户测试) if __name__ __main__: print(erp管理系统登录模块的验证) # 只完成登录参数校验的验证测试和登录的测试 # 第一种方法在main方法中指定需要测试测试方法 # unittest.main(defaultTest[ErpLogin1.test02_loginCheckParam,ErpLogin1.test01_login]) # 第二种方法 采用测试套件TestSuite # testSuite unittest.TestSuite() # 添加需要测试的测试方法 # testSuite.addTest(testErpLogin1(test02_loginCheckParam))#本质上就是testsuite来实现的 # testSuite.addTest(ErpLogin1(test01_login))#这里使用的是方法名 # 这里也可以使用addTests()参数是可迭代对象其实就是列表 # testSuite.addTests([ErpLogin1(test02_loginCheckParam), ErpLogin1(test01_login)]) # 执行测试方法将测试的结果使用文本的方式打印出来 # unittest.TextTestRunner().run(testSuite) # 第三种方法通过类加载器的方式来实现 # 获取测试套件 suite unittest.TestSuite() # 发现测试方法并加载测试方法 testMotheds unittest.defaultTestLoader.discover(start_dirrD:\pyhton-product\pythonbase\nnittest_stu,pattern*_login1.py) # 添加需要测试的方法 suite.addTests(testMotheds) # 执行测试 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 使用默认类加载器的方式来加载并执行测试方法适用于多个测试类suiteunittest.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[])案例import unittest # 需求在测试登录功能之前必须先要打开浏览器加载浏览器关闭浏览器 # 打开浏览器和关闭浏览器是每一次登录之前就要做的事因此在进行登录测试之前 # 先打开浏览器然后登录测试关闭浏览器 class TestLogin(unittest.TestCase): def setUp(self) - None: print(打开浏览器加载浏览器) def tearDown(self) - None: print(关闭浏览器) def test01_login(self): print(test01_login) def test02_login2(self): print(test02_login2) if __name__ __main__: print(main) unittest.main(defaultTest[TestLogin.test01_login, TestLogin.test02_login2])结果main 打开浏览器加载浏览器 test01_login 关闭浏览器 打开浏览器加载浏览器 test02_login2 关闭浏览器 .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s4.2 setUpClass()和tearnDownClass()使用在测试类之前或者之后执行一次适用场景一般用于连接数据库和关闭数据库连接以及一些日志对象的销毁导包import unittest 和 需要导入的数据库连接类继承继承TestCase类重写setUpClass和tearDownClass方法必须在方法前加装饰器classmethod运行测试方法unittest.main(defaultTest[])案例# database.py class DataBase(): def link(self): print(连接数据库) def close(self): print(关闭数据库)import unittest # 导入数据库连接类所在的包自定义 import database # 需求在测试登录功能之前必须先要打开浏览器加载浏览器关闭浏览器 # 打开浏览器和关闭浏览器是每一次登录之前就要做的事因此在进行登录测试之前 # 先打开浏览器然后登录测试关闭浏览器 class TestLogin(unittest.TestCase): classmethod def setUpClass(cls) - None: db database.DataBase() db.link() classmethod def tearDownClass(cls) - None: database.DataBase().close() def setUp(self) - None: print(打开浏览器加载浏览器) def tearDown(self) - None: print(关闭浏览器) def test01_login(self): print(test01_login) def test02_login2(self): print(test02_login2) if __name__ __main__: print(main) unittest.main(defaultTest[TestLogin.test01_login, TestLogin.test02_login2])结果main 连接数据库 打开浏览器加载浏览器 test01_login 关闭浏览器 打开浏览器加载浏览器 test02_login2 关闭浏览器 关闭数据库 .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s4.3 setUpModule()和tearDownModule()的使用函数级别的在模块之前或者之后执行一次在python中所谓的模块指的就是一个py文件。setUpModule和setDownModule都是定义在木块中的函数这个做个演示即可使用的场景不是很多。因为测试用例一般是独立的不可以相互关联。案例# database.py class DataBase(): def link(self): print(连接数据库) def close(self): print(关闭数据库)import unittest import database # 需求在测试登录功能之前必须先要打开浏览器加载浏览器关闭浏览器 # 打开浏览器和关闭浏览器是每一次登录之前就要做的事因此在进行登录测试之前 # 先打开浏览器然后登录测试关闭浏览器 def setUpModule(): print(setUpAndtearDown.py模块之前) def tearDownModule(): print(setUpAndtearDown.py模块之后) class TestLogin(unittest.TestCase): classmethod def setUpClass(cls) - None: db database.DataBase() db.link() classmethod def tearDownClass(cls) - None: database.DataBase().close() def setUp(self) - None: print(打开浏览器加载浏览器) def tearDown(self) - None: print(关闭浏览器) def test01_login(self): print(test01_login) def test02_login2(self): print(test02_login2) if __name__ __main__: print(main) unittest.main(defaultTest[TestLogin.test01_login, TestLogin.test02_login2])结果main .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK setUpAndtearDown.py模块之前 连接数据库 打开浏览器加载浏览器 test01_login 关闭浏览器 打开浏览器加载浏览器 test02_login2 关闭浏览器 关闭数据库 setUpAndtearDown.py模块之后 Process finished with exit code 04.4 忽略测试用例在执行一些测试用例的时候我们可能会对一些测试用例进行忽略不需要进行测试在unittest中有两种忽略方式无条件忽略和有条件忽略。unittest.skip(des)参数为忽略的原因unitest.skipIf()两个参数第一个参数是忽略的条件为真就忽略第二个为什么忽略的描述。unittest.skipUnless()和unitest.skipIf()一样只不过是为假的时候才会忽略。备注unittest.skip(des)放在方法之前表示测试方法跳过忽略unittest.skip(des)放在模块上面直接跳过整个模块七、数据驱动1、为什么要有数据驱动在软件测试中测试用例的数据往往都是写在excel表格中而不是我们去拿着软件边想边测试因此在进行测试用例的时候我们需要将测试数据测试用例从excel中读取出来然后让测试方法去执行我们写的测试用例。2、驱动模式介绍数据驱动关键字驱动将核心业务逻辑封装成方法然后直接调用方法混合驱动模式关键字数据驱动——》市场主流行为测试驱动Lettuce3、DDTDDT定义data driver test数据驱动测试点。特点可以完美的和unittest结合使用通过数据驱动将我们写的测试用例读取出来然后执行测试用例。DDT的使用通过装饰器的形式来调用。装饰器完成某种特定功能的函数就是java中的注解在python中的定义以开头装饰器主要有两种一种是类装饰器另一种是函数装饰器。4、DDT中的装饰器重点ddt()类装饰器声明当前类是ddt的框架data()函数装饰器用于给测试方法传递数据其中*表示格式化传递的数据如果传递的是列表字典元组的嵌套就会把列表字典元组进行格式化unpack()函数装饰器将传输的数据进行解包一般作用于元组tuple和列表listfile_data()函数装饰器可以直接读取json和ymal文件5、data的使用传值类型data可以传递的数据类型有数字float、int、bigint、double、compix、字符串string、列表list、元组tuple、集合setimport unittest from ddt import ddt, data ddt # 类装饰器表示要使用ddt框架 class DataSend(unittest.TestCase): # 传递数字 data(10) def test01_data_send_int(self, param1): print(param1) # 传递字符串 data(string) def test02_data_send_string(self, param1): print(param1) # 传递元组 data((1, 2, 3)) def test03_data_send_tuple(self, param1): print(param1) # 传递列表 data([4, 5, 6, 7]) def test04_data_send_list(self, param1): print(param1) # 传递字典 data({name: bugchen, age: 18}) def test05_data_send_dict(self, param1): print(param1) if __name__ __main__: unittest.main() # 结果 # 10 # string # (1, 2, 3) # [4, 5, 6, 7] # {name: bugchen, age: 18}传值个数data传值的个数为一个的时候测试方法执行一次传递多个值的时候就执行多次总的来说传递几个值测试方法就会执行几次import unittest from ddt import ddt, data ddt class DataNums(unittest.TestCase): data(12) def test01_one(self, param1): print(param1) data(1, 2) def test02_two(self, param1): print(param1) data([a]) def test03_three(self, param1): print(param1) data([b], [b, c]) def test04_four(self, param1): print(param1) if __name__ __main__: unittest.main() # 结果 # 12 # 1 # 2 # [a] # [b] # [b, c]6、unpack的使用从上面我们可以看出虽然传递多个参数的时候我们可以执行多次但是当我们在测试方法中接收数据的时候只能接收一种数据类型的参数对于列表元组这样的数据类型我们该怎么接收呢总不能接收之后在处理吧因此unpack就是用来解包的对于元组和类型列表类型的参数它可以解析成多个单个值比如123解析之后就是123三个值这个时候测试方法需要三个参数来进行接收[‘1’,‘2’,‘3’]经过解析之后就是123三个字符串这个时候也需要三个参数进行接收不然会报错参数个数必须一一对应。import unittest from ddt import ddt, data, unpack ddt class DataNums(unittest.TestCase): data([1, 2, 3]) # 数据类型是列表 unpack # 解包 12 3需要三个参数接收 def test05(self,p1,p2,p3):#参数于解包后的参数个数对应 print(p1) print(p2) print(p3) if __name__ __main__: unittest.main() # 结果 # 1 # 2 # 3备注使用unpack需要注意集合不能解包如果是数字或者字符串不需要解包列表可以解包元组可以解包字典可以解包但是测试方法接收的值必须于字典的键一致import unittest from ddt import ddt, data, unpack ddt class DataNums(unittest.TestCase): data({name: bugchen, age: 18}, {name: chen, age: 28}) unpack # 因为字典中有两个键因此参数需要用两个键来接收并别键的名称一致 #def test06(self, p1, p2):#不一致报错 # print(p1) # print(p2) def test06(self,name,age):#一致运行成功 print(name) print(age) if __name__ __main__: unittest.main() # 结果 # OK # bugchen # 18 # chen # 28八、unittest实战需求规格说明书随机输入三个正整数个数判断是否构成三角形以及构成的什么边的三角形。暂且不考虑正整数的范围测试需求如果不能构成三角行输出“不能构成三角形”如果输入非法提示“非法输入”普通三角形用1表示等腰三角形用2表示等边三角形用3表示。实战要求编写测试用例形成测试用例表并从测试用例表中读取测试用例执行测试用例形成测试报告。1、测试思路1.1 等价类划分1.1.1随机输入三个正整数个数划分为两个等价类三个正整数有效、三个非正整数无效三个正整数 1种其中一个非正整数小数、字符、负数、0 4种1.1.2 判断是否构成三角形以及构成的什么边的三角形划分为两个等价类构成和不构成构成普通等腰等边 5种不构成任意两边之和小于等于第三边 6种2、编写测试用例TriangleTestCase.xlsx暂且只写一部分3、python自动化思路导入测试模块——》读取测试用例数据驱动——》编写测试方法——》执行测试用例——》形成测试报告——》自动发送测试报告给组长或者经理暂且不做测试部分的代码如下# 测试模块负责三角模块的测试 # 导入unittest测试单元 import xlrd from xlutils import copy # 在写入excel表的时候需要先拷贝再写入 import unittest # 导入数据驱动 from ddt import ddt, data, unpack # 导入待测试的测试用例数据的模块 from day9.data import TriangleData # 导入需要测试的模块 from day9.function import triangle ddt # 声明使用ddt框架 class TestTriangle(unittest.TestCase): # 获取TriangleData模块下的TriangleData类并通过TriangleData获取测试用例数据 triangleData TriangleData.TriangleData().triangleData # print(triangleData) data(*triangleData) # 传入数据 *表示解析数据格式解析成列表的格式 unpack # 解包的数据类型为列表、元组、字典 def test01_isTriangle(self, row, a, b, c, except_res): t triangle.Triangle() # 执行测试用例真实结果 real_res t.isTriangle(a, b, c) # 将执行的结果写入工作簿 write_isTriangle_result(row, real_res, except_res) # 断言进行预期结果与真实结果的判断 self.assertEqual(except_res, real_res) # 注意先传入预期结果在传入实际结果 def write_isTriangle_result(row, real_res, except_res): # 将实际结果和预期结果 is_pass 否 if except_res real_res: is_pass 是 # 将处理的结果写入cal_test表中 # 打开源文件并保留源文件的数据格式 wb xlrd.open_workbook(filenamerD:\pyhton-product\day9\testCases\TriangleTestCase.xlsx, encoding_overrideutf-8) # 复制原始的工作簿 c_wb copy.copy(wb) # 获取工作表 c_sheet c_wb.get_sheet(0) # 写入数据 c_sheet.write(row, 5, real_res) c_sheet.write(row, 6, is_pass) # 保存复制下来的表格 c_wb.save(rD:\pyhton-product\day9\testCases\TriangleTestCase.xlsx) # 这一部分用于执行测试用例和生成测试报告 # if __name__ __main__: # unittest.main()每个包的含义测试报告最后感谢每一个认真阅读我文章的人礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走这些资料对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库这个仓库也陪伴我走过了最艰难的路程希望也能帮助到你凡事要趁早特别是技术行业一定要提升技术功底。