单元测试本质(通过一段代码去验证另外一段代码)
单元测试框架提供功能
1.提供用例组织与执行
当测试用例达到成百上千条时,就产生了扩展性与维护性等问题,此时就需要考虑用例的规范与组织问题了。单元测试框架便能很好的解决这个问题
2.提供丰富的断言方法
不论是功能测试还是单元测试,在用例完成之后都需要将实际结果与预期结果进行比较(断言),从而断定用例是否执行通过。单元测试框架一般会提供丰富的断言方法。例如:相等\不相等,包含\不包含,True\False的断言方法等
3.提供丰富的日志
当测试用例执行失败时能抛出清晰的失败原因,当所有用例执行完成之后能提供丰富的执行结果。例如,总执行时间、失败用例数、成功用例数等
认识单元测试,创建被测试文件 calculator.py
class Calculator:
def __init__(self,a,b):
self.a=a
self.b=b
def add(self):
return self.a+self.b
def sub(self):
return self.a-self.b
def mul(self):
return self.a*self.b
def div(self):
return self.a/self.b
创建test_calculator单元测试类,导入calculator文件里的Calculator类
from calculator import Calculator
import unittest
class TestCalculator(unittest.TestCase):
def setUp(self):
print("test start")
def tearDown(self):
print("test end")
def test_add(self):
c=Calculator(3,5)
result=c.add()
self.assertEqual(result,1)
def test_sub(self):
c = Calculator(6, 5)
result = c.sub()
self.assertEqual(result, 1)
def test_mul(self):
c = Calculator(6, 5)
result = c.mul()
self.assertEqual(result, 30)
def test_div(self):
c = Calculator(12, 6)
result = c.div()
self.assertEqual(result, 2)
if __name__=="__main__":
suit=unittest.TestSuite()
suit.addTest(TestCalculator("test_sub"))
suit.addTest(TestCalculator("test_mul"))
suit.addTest(TestCalculator("test_div"))
suit.addTest(TestCalculator("test_add"))
runner=unittest.TextTestRunner()
runner.run(suit)
执行结果:
结果分析:
每执行一条测试用例对应就会走一次setUp、tearDown方法
测试用例执行成功用"."表示,执行失败用"F"表示
测试用例的执行顺序由测试套件的添加顺序控制,由以上可看出虽然test_add是第一个测试用例,但是在测试组件中最后添加,所以最后执行
unittest单元测试框架生成HTML报告
步骤:
1.下载HTMLTestRunner.py文件,下载路径https://github.com/SeldomQA/HTMLTestRunner
注:git下载命令:git clone https://github.com/SeldomQA/HTMLTestRunner.git (标黄为项目下载地址)
2.把下载好的HTMLTestRunner.py文件复制到…/Python38/Lib目录下
3.打开python shell, 输入:import HTMLTestRunner 验证是否安装成功,若不报错则安装成功
4.若项目中要使用HTMLTestRunner生成测试报告,则放入被测项目中,若哪个模块需要直接import即可
代码示例(简易版):
import unittest
from HTMLTestRunner import HTMLTestRunner
class Case_assert_1(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_ok(self):
self.assertEqual(1,1)
def test_faile(self):
self.assertEqual(1,2)
def test_error(self):
raise Exception
class Case_assert_2(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_ok(self):
self.assertTrue(True)
class Case_assert_3(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_error(self):
raise Exception
class Case_assert_4(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_faile(self):
self.assertEqual(1,3)
if __name__ == "__main__":
suite = unittest.TestSuite()
suite.addTest(Case_assert_1('test_ok'))
suite.addTest(Case_assert_1('test_faile'))
suite.addTest(Case_assert_1('test_error'))
suite.addTest(Case_assert_2('test_ok'))
suite.addTest(Case_assert_3('test_error'))
suite.addTest(Case_assert_4('test_faile'))
with open('E:\\HwTestReport.html', 'wb') as report:
runner = HTMLTestRunner(stream=report,
verbosity=2,
title='HTMLTestRunner 测试',
description='带饼图,带详情'
)
runner.run(suite)
代码解析:
stream:指定生成的HTML测试报告,必填
verbosity:指定日志的级别,默认为1,。如果想得到更详细的日志,可将参数修改为2
title:指定测试用例标题,默认为None
description:指定测试用例描述,默认为None
综上可在E盘根目录下看到名为HwTestReport.html的测试报告,如下图:
更易读的测试报告
现生成的测试报告可读性差,因只生成了类名、测试用例名,如果命名不规范很难明白测试用例所测功能,
为了解决以上问题,可在类或方法下方,添加’’‘XXX’’'或者""“XXX”""解决这一问题
代码示例:
class Case_assert_4(unittest.TestCase):
'''断言case类四'''
def setUp(self):
pass
def tearDown(self):
pass
def test_faile(self):
'''测试失败case,断言1==3'''
self.assertEqual(1,3)
再次查看生成测试报告,如图:
测试报告名称
如果不想每次执行测试用例生成测试报告被覆盖,可以用时间作为测试报告名称,修改代码如下:
#now_time=time.strftime("%Y-%m-%d %H:%M:%S")
now_time = time.strftime("%Y-%m-%d %H_%M_%S")
print(now_time)
with open('E:\\'+now_time+'.html', 'wb') as report:
runner = HTMLTestRunner(stream=report,
verbosity=2,
title='HTMLTestRunner 测试',
description='带饼图,带详情'
)
runner.run(suite)
注:文件名格式不能带":" 所以 time.strftime("%Y-%m-%d %H:%M:%S") 这样写会报错,改为下面方式运行成功,这样每次生成的文件都是按时间格式生成的新文件