目录
模块定义
- unittest是python自带的单元测试框架。
- 要使用unittest模块就需要明确什么样的测试用例才能被unittest组织并执行,下面依次进行介绍。
python代码批量生成的测试用例所包含的方法
- 比如在python实现的接口自动化测试过程中,通过python代码批量生成测试用例类(继承unittest.TestCase),在类中实现以test开头的测试用例方法,一个测试用例类可以包含多个test开头的测试用例方法,然后再通过unittest模块的关键方法实现组织测试用例批量执行、断言并生成测试结果。以下列出完整的一个测试类包含的方法:
- class PushOrder(unittest.TestCase) ,生成一个类并继承unittest.TestCase
- def setUp(self) ,用于在每个用例执行前做初始化工作,如连接数据库、加载EXCEL等。一条用例执行一次,多条用例执行多次。
- def tearDown(self) 用于执行完测试用例后的收尾工作,比如断开数据库连接,关闭文件等。一条用例执行一次,多条用例执行多次。
- def test_pushOrder(self), 在这个方法中完成了请求入参的拼接、请求的触发、根据检查点对响应结果做校验、响应结果的存储、依赖数据的存储、执行结果的写入等。
- 注,测试固件setUp和tearDown每次执行用例都会重新执行,如果想更高效可以使用类方法,可以用类方法setUpClass()在所有用例执行前就一次性的准备好环境,用类方法tearDownClass()所有用例执行完后再清理环境。
-
... class ApushOrder(unittest.TestCase): """ApushOrder""" @classmethod def setUpClass(cls): print "This setUpClass() method only called once." @classmethod def tearDownClass(cls): print "This tearDownClass() method only called once too." ...
-
- unittest会自动识别test开头的方法为测试代码,不以test开头的方法不会被unittest组织并执行。
- unittest对test开头的测试用例方法的相关装饰器包括:
- @unittest.skip(reason) 不执行该用例,跳过。
- @unittest.skipif(condition, reason) 条件为真跳过该用例。
- @unittest.skipUnless(condition, reason) 条件为假跳过该用例。
- @unittest.expectedFailure 将测试用例标记为“预期失败”。
- @unittest.SkipTest(resaon) 跳过测试方法,可以在测试方法或者setUp()中调用该方法。
unittest模块组织并执行上述用例的关键方法
- 主要流程就是加载测试用例->把测试用例加入到测试套件中->通过runner执行测试套件。
- Unittest.TestLoader()、Unittest.TestSuit()、Unittest.TextTestRunner()。
- Unittest.TestLoader()加载测试用例类,加载测试用例相关方法:
- loadTestsFromTestCase()
- testcase = unittest.TestLoader().loadTestsFromTestCase(testCaseClass),testCaseClass即PushOrder类,这里的类必须是Unittest.TestCsse的子类。
- loadTestsFromModule()
- testcase = unittest.TestLoader().loadTestsFromModule(module, pattern=None),module是测试用例所在的模块。
- loadTestsFromName()
- testcase = unittest.TestLoader().loadTestsFromName(name, module=None),name是测试用例的方法名,使用的格式是'modlue.class.method'。
- loadTestsFromNames()
- testcase = unittest.TestLoader().loadTestsFromNames(),括号中是用例列表,使用的格式是['modlue.class.method','modlue.class.method',...]。
- discover(start_dir被测试模块所在目录, pattern正则匹配要执行的测试用例文件, top_level_dirt测试模块的顶层目录,默认为None)
- discover = unittest.TestLoader().discover('./script', pattern='*_test.py'), *_test.py根据自动生成的文件名来处理。
- runner = unittest.TextTestRunner()
- runner.run(discover )
- 该方法相当于直接形成了测试套件,所以实现后可以直接通过runner去运行。
- loadTestsFromTestCase()
- Unittest.TestSuit()测试套件类,来组织所有测试用例,生成suite对象后调用的相关方法包括:
- addTests(), 参数可以是列表list或者元组tuple。
- suite = unittest.TestSuite()
- suite.addTests(map(PushOrder,['test_pushOrder1','test_pushOrder2' ]))
- addTest()
- suite = unittest.TestSuite()
- suite.addTest(testcase),如果想单个调用测试用例,也可以通过以下写法将测试用例加入到测试套件中:
- suite.addTest(PushOrder('test_pushOrder1'))
- suite.addTest(PushOrder('test_pushOrder2'))
- addTests(), 参数可以是列表list或者元组tuple。
- Unittest.TextTestRunner()测试执行器类,生成runner对象后调用run()方法执行上面通过testsuit组织好的测试套件suite,相关方法:
- runner = unittest.TextTestRunner()
- runner.run(suite)
- Unittest.main()可以实现单独执行所在的测试用例类,具体体现为:
# encoding = utf-8 import unittest, requests from utils.operate_excel import * from utils.db_handler import * import os, sys, json from utils.ParseExcel import * from interface.create_script1 import * from utils.LogInfo import * class ApushOrder (unittest.TestCase): def setUp(self): XXXX def test_pushOrder1(self): XXXX def tearDown(self): XXXX if __name__ == '__main__': unittest.main()
- 断言,Unittest的断言方法包括如下
- assertEqual(a,b,msg) a等于b则测试通过
- assertIsInstance(a,b,msg) a属于b类型则测试通过
- assertIn(a,b,msg) a包含于b中则测试通过
- assertTrue(a,msg) a为真则测试通过
- assertNone(a.msg) a为None则测试通过
接口自动化测试时的注意事项
- 生成的一个*_test.py的测试用例文件,里面包含一个接口的多个用例的执行顺序。
- 一个测试类中依次实现了三条测试用例test_zpushOrder1, test_bpushOrder2, test_apushOrder3,可以在该文件下直接通过unittest框架unittest.main()执行,执行后会发现这三条用例的执行顺序是随机的,并不是按照编写顺序执行(unittest.main()相当于调用TextTestRunner中的run来执行)。
- 用例的执行顺序不是按照编写顺序,执行顺序是按照ASCII码的顺序加载执行,数字与字母的顺序为0-9, A-Z,a-z,即test_pushOrder1会比test_pushOrder3先执行,所以在同一个接口的.py文件中可以通过这个规则来规定用例执行顺序。
- 如果一个接口类文件A_test.py里有三条用例,需有先后执行顺序的话,可以按照执行规则来命名用例名,如test_aorder,test_border,test_corder后运行。也可以通过TestSuite来处理,测试用例会按照添加顺序执行,可以通过addTests添加用例列表,也可以通过addTest逐个添加用例,比如:
-
suite = unittest.TestSuite() tests = [ApushOrder("test_zpushOrder1"),ApushOrder("test_bpushOrder2"), ApushOrder("test_apushOrder3")] suite.addTests(tests) # 上两句就相当于 suite.addTests(map(PushOrder,['test_pushOrder1','test_pushOrder3' ,'test_pushOrder2'])) runner = unittest.TextTestRunner(verbosity=2) runner.run(suite)
-
- 比如有三个接口需要做接口自动化测试A,B,C,通过python代码批量生成的三个*_test.py的测试用例文件,叫A_test.py、B_test.py、C_test.py,这三个接口是有前后关联关系的,即A-B-C,每个接口有若干条测试用例,A有3条用例,B有1条用例,C有2条用例。如何通过unittest去组织接口用例并执行。
- 仍然通过TestSuite实现,可以通过addTests添加用例列表,也可以通过addTest逐个添加用例,比如:
suite = unittest.TestSuite() tests = [ApushOrder("test_zpushOrder1"),ApushOrder("test_bpushOrder2"), ApushOrder("test_apushOrder3"), BrepayPlan("test_repayPlan1"),CpreRepayment("test_1preRepaymentTrial"),CpreRepayment("test_2preRepaymentApply")] suite.addTests(tests) runner = unittest.TextTestRunner(verbosity=2) runner.run(suite)
- 仍然通过TestSuite实现,可以通过addTests添加用例列表,也可以通过addTest逐个添加用例,比如:
- 如果不需要考虑执行顺序问题,还可以通过TestLoader方法来加载测试用例,如最上方绿色字体相关的代码。
- testcase = unittest.TestLoader().loadTestsFromTestCase(testCaseClass) 即批量生成的.py文件的模块下的类名
- testcase = unittest.TestLoader().loadTestsFromName('ApushOrder_test.ApushOrder') 即批量生成的.py文件的模块名.类名
- testcase = unittest.TestLoader().loadTestsFromNames(['ApushOrder_test.ApushOrder','BrepayPlan_test.BrepayPlan','CpreRepayment_test.CpreRepayment'])
- suite = unittest.TestSuite()
- suite.addTest(testcase)
- TestSuit还可以套TestSuit。
HTML测试报告相关
- 通过HTMLTestRunner.py文件可以将测试结果以.html的方式展示,使测试结果更加清晰。该文件可以网上下载,但是使用前要确认下载是python2语法还是python3语法,如果和当前使用的python版本不一致需要修改部分代码。
- 相关代码和执行结果,verbosity控制结果的输出,0是简单报告,1是一般报告,2是详细报告。
-
# -*- coding:utf-8 -*- # author:Chang JinLing # datetime:2021/2/23 10:49 import sys import unittest sys.path.append("./script") from utils.HTMLTestRunner import HTMLTestRunner # 生成测试报告 import time from script.ApushOrder_test import ApushOrder from script.BrepayPlan_test import BrepayPlan from script.CpreRepayment_test import CpreRepayment if __name__ == "__main__": suite = unittest.TestSuite() tests = [ApushOrder("test_pushOrder1"), ApushOrder("test_pushOrder2"), ApushOrder("test_pushOrder3"), BrepayPlan("test_repayPlan1"), CpreRepayment("test_1preRepaymentTrial"), CpreRepayment("test_2preRepaymentApply")] suite.addTests(tests) now = time.strftime("%Y-%m-%d %H_%M_%S") filename = './report/' + now + '_result.html' fp = open(filename, "wb") runner = HTMLTestRunner(stream=fp, title="接口自动化测试", description="接口自动化测试结果报告", verbosity=2) runner.run(suite) fp.close()
- 如果只是想简单的输出测试结果也可以通过输出.txt文件来展示。
- 相关代码和执行结果
-
# -*- coding:utf-8 -*- # author:Chang JinLing # datetime:2021/2/23 10:49 import sys import unittest sys.path.append("./script") import time from script.ApushOrder_test import ApushOrder from script.BrepayPlan_test import BrepayPlan from script.CpreRepayment_test import CpreRepayment if __name__ == "__main__": suite = unittest.TestSuite() tests = [ApushOrder("test_pushOrder1"), ApushOrder("test_pushOrder2"), ApushOrder("test_pushOrder3"), BrepayPlan("test_repayPlan1"), CpreRepayment("test_1preRepaymentTrial"), CpreRepayment("test_2preRepaymentApply")] suite.addTests(tests) with open('UnittestTextReport.txt', 'a') as f: runner = unittest.TextTestRunner(stream=f, verbosity=2) runner.run(suite) f.close()