unittest框架
案例
项目代码
# 项目代码
class count:
def __init__(self, a, b):
self.a = a
self.b = b
# 计算加法
def add(self):
return self.a + self.b
# 减法
def Subtraction(self):
return self.a - self.b
测试代码:
import unittest
from day04.calc import count
'''
unittest是python的单元测试框架,不需要安装直接导入使用即可
测试用例类需要继承unittest.TestCase
属性该类的测试用例其实就是一个实例方法
该测试用例方法,必须要使用test开头
CountTest.main():执行该测试类中所有测试用例
'''
# 测试用例
class CountTest(unittest.TestCase):
# 测试加法
def test_add(self):
# 调用项目代码中的加法
# 类的实例化
c1 = count(5, 6)
# 调用方法
r = c1.add()
# 测试的本质永远是实际结果和需求结果的比较
# 断言
self.assertEqual(r, 12)
# 测试减法
def test_sub(self):
# 类的实例化
c2 = count(6, 3)
# 调用减法
r = c2.Subtraction()
# 断言
self.assertEqual(r, 3)
if __name__ == '__main__':
# 执行测试用例(执行该测试类下面的所有测试用例)
CountTest.main()
二、unittest模块说明
- TestCase:一个TestCase的实例就是一个测试用例,是一个完整的测试流程,包括测试前准备环境的搭建(setUp),实现测试过程的代码(run),测试后环境的还原(tearDown).
- Test Suite:把多个测试用例集合在一起来执行。可以通过addTest加载TestCase到Test Suite(测试套件)中,从而返回一个TestSuite实例。
- Test Runner:测试的执行,通过TextTestRunner类提供的run()方法来执行Test Suite/TestCase。Test Runner可以使用图形界面,文本界面,或者返回一个特殊的值的方式来表示测试执行的结果。
- Test Fixture:对一个测试用例环境的初始化和清除。通过覆盖TestCase的setUp()和tearDown()方法来实现。tearDown()为下一个测试用例提供一个干净的环境。
三、常见的断言方式
# 如果两个值相等,则测试通过
assertEqual(r, 12)
# 如果两个值不相等,则测试通过
assertNotEqual(r, 12)
# 判断返回值是否为true,如果为true则测试通过,msg后面可以自定义失败信息,可以写也可以不写
self.assertTrue(r, msg="测试不通过")
#.判断第一个参数是否在第二个参数中,简言之也就是检查第二个参数是否包含第一个参数。
self.assertIn(r, new_names)
# 如果第一个值不在第二个值中,则测试通过
self.assertNotIn(r, new_names)
import random
# 项目代码
class count:
def __init__(self, a, b):
self.a = a
self.b = b
# 计算加法
def add(self):
return self.a + self.b
# 减法
def Subtraction(self):
return self.a - self.b
# 返回true或者false
def func1(self):
if self.a - self.b >= 10:
return True
else:
return False
def func2(self):
names = ["张三1", '李四1', '王五1', "赵六1"]
return random.choice(names)
import unittest
from day04.calc import count
'''
unittest是python的单元测试框架,不需要安装直接导入使用即可
测试用例类需要继承unittest.TestCase
属性该类的测试用例其实就是一个实例方法
该测试用例方法,必须要使用test开头
'''
# 测试用例
class CountTest(unittest.TestCase):
# 测试加法
def test_add(self):
# 调用项目代码中的加法
# 类的实例化
c1 = count(5, 6)
# 调用方法
r = c1.add()
# 测试的本质永远是实际结果和需求结果的比较
# 断言
self.assertNotEqual(r, 12)
# 测试减法
def test_sub(self):
# 类的实例化
c2 = count(6, 3)
# 调用减法
r = c2.Subtraction()
# 断言
self.assertEqual(r, 3)
def test_func1(self):
# 类的实例化
c3 = count(7, 5)
# false
r = c3.func1()
self.assertTrue(r, msg="测试不通过")
def test_func2(self):
# 类的实例化
c4 = count(4,5)
# 调用方法
r = c4.func2()
new_names = ["张三", '李四', '王五', "赵六", "张无忌", "周芷若", "赵敏"]
# 取出某个人名,判断其在不在某个值中
# self.assertIn(r, new_names)
self.assertNotIn(r, new_names)
if __name__ == '__main__':
# 执行测试用例(执行该测试类下面的所有测试用例)
CountTest.main()
四、Test Fixture(对测试环境的初始化和清除)
测试用例依赖的测试数据准备活动就可以在环境的初始化完成,清除的时候就是初始化添加了什么数据,清除的时候就需要将什么数据给删除掉
-
setUpModule/tearDownModule:在整个模块的开始和结束时被执行。
_______________这是setUpModule_____________ ***********test_add************ ***********test_sub************ ***********test_func1************ ***********test_func2************ _______________这是tearDownModule_____________
-
setUpClass/tearDownClass: 在测试类的开始和结束时被执行。
针对某个具体测试类而言的
_______________这是setUpModule_____________ _______________这是setUpClass_____________ ***********test_add************ ***********test_sub************ ***********test_func1************ ***********test_func2************ _______________这是tearDownClass_____________ _______________这是tearDownModule_____________
-
setUp/tearDown:在测试用例的开始与结束时被执行 注意:setUpClass/tearDownClass的写法稍有不同,首先通过@classmethod进行装饰,其次方法的参数为cls,也可以是别的。每一个上面都要进行装饰
用例级别的,每一个测试用户开始执行之前都需要执行用例的初始化,用例执行结束之后,执行用例的清除
_______________这是setUpModule_____________ _______________这是setUpClass_____________ _______________这是setUp_____________ ***********test_add************ _______________这是tearDown_____________ _______________这是setUp_____________ ***********test_sub************ _______________这是tearDown_____________ _______________这是setUp_____________ ***********test_func1************ _______________这是tearDown_____________ _______________这是setUp_____________ ***********test_func2************ _______________这是tearDown_____________ _______________这是tearDownClass_____________ _______________这是tearDownModule_____________
import unittest from day04.calc import count ''' unittest是python的单元测试框架,不需要安装直接导入使用即可 测试用例类需要继承unittest.TestCase 属性该类的测试用例其实就是一个实例方法 该测试用例方法,必须要使用test开头 ''' # 模块的初始化 def setUpModule(): print("_______________这是setUpModule_____________") # 模块的清除 def tearDownModule(): print("_______________这是tearDownModule_____________") # 测试用例 class CountTest(unittest.TestCase): # 类级别的初始化 @classmethod def setUpClass(cls) -> None: print("_______________这是setUpClass_____________") # 类级别的清除 @classmethod def tearDownClass(cls) -> None: print("_______________这是tearDownClass_____________") # 用例级别的初始化 def setUp(self) -> None: print("_______________这是setUp_____________") def tearDown(self) -> None: print("_______________这是tearDown_____________") # 测试加法 def test_add(self): print("***********test_add************") # 调用项目代码中的加法 # 类的实例化 c1 = count(5, 6) # 调用方法 r = c1.add() # 测试的本质永远是实际结果和需求结果的比较 # 断言 self.assertNotEqual(r, 12) # 测试减法 def test_sub(self): print("***********test_sub************") # 类的实例化 c2 = count(6, 3) # 调用减法 r = c2.Subtraction() # 断言 self.assertEqual(r, 3) def test_func1(self): print("***********test_func1************") # 类的实例化 c3 = count(23, 5) # false r = c3.func1() self.assertTrue(r, msg="测试不通过") def test_func2(self): print("***********test_func2************") # 类的实例化 c4 = count(4,5) # 调用方法 r = c4.func2() new_names = ["张三", '李四', '王五', "赵六", "张无忌", "周芷若", "赵敏"] # 取出某个人名,判断其在不在某个值中 # self.assertIn(r, new_names) self.assertNotIn(r, new_names) if __name__ == '__main__': # 执行测试用例(执行该测试类下面的所有测试用例) CountTest.main()
五、Test Suite创建测试套件
测试套件就类似于测试单,测试用例是属于测试套件的,一个测试套件中可以有多条测试用例
1.添加单个用例到测试套件
import unittest
from day04.CountTest import CountTest
'''
通过执行器执行之后 一个点 就代表通过了一条测试用例
..F
'''
# 方法1:可以通过addTest()加载TestCase到TestSuite中。用于少量的测试用例
# 创建测试套件
suite = unittest.TestSuite()
# 给测试套件添加测试用例
suite.addTest(CountTest('test_add'))
suite.addTest(CountTest('test_sub'))
suite.addTest(CountTest('test_func1'))
# 创建执行器
runner = unittest.TextTestRunner()
# 使用上面创建的执行器,执行测试套件
runner.run(suite)
2.同时添加多个测试用例
#方法2:同时添加多个测试用例到套件之中
import unittest
from day04.CountTest import CountTest
# 创建测试套件
suite = unittest.TestSuite()
# 给测试套件添加测试用例
cases = [CountTest('test_func2'),CountTest('test_func1')]
# addTests可以接受一个列表
suite.addTests(cases)
# 生成执行器
runner = unittest.TextTestRunner()
runner.run(suite)
3.将某个测试类中的所有测试用例添加到测试套件中
# 方法3:添加整个类中的测试用例到套件中
import unittest
from day04.CountTest import CountTest
# 创建测试套件
suite = unittest.TestSuite()
# 给该测试类添加测试用例
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(CountTest))
# 创建测试执行器
runner = unittest.TextTestRunner()
# 执行套件
runner.run(suite)
4.模糊匹配
# 模糊匹配
import unittest
# 加载路径
casepath = "../day04"
# 指定匹配的规则,会自动生成测试套件,将用例添加进去
suite = unittest.defaultTestLoader.discover(start_dir=casepath, pattern='Cou*.py')
# 创建执行器
runner = unittest.TextTestRunner()
# 执行测试用例
runner.run(suite)
六、测试跳过
# @unittest.skip("该用例所对应的功能未开发完成")
# skipIf 如果为true则跳过不执行,
# @unittest.skipIf(5>4, "因为我要测试一下")
# 如果为true则报错,如果为false则跳过
# @unittest.skipUnless(3>4, "因为我要测试一下")
# 不论结果如何都是失败
# @unittest.expectedFailure("功能未能实现")
# 如果断言失败,不计入执行case数目中
七、生成测试报告
import unittest
import time
import os
from common.HTMLTestRunner import HTMLTestRunner
# 测试报告的存放路径
report_path = "./report/"
# 测试报告的标题
report_title = "冒烟测试"
# 测试的描述
report_desc = "本次测试是对于加减法功能的测试"
# 做一个判断,如果有了report目录直接使用,没有则创建
if not os.path.exists(report_path):
# 没有则创建
os.mkdir(report_path)
# 构建获取时间日期,作为报告的名字,避免重复
gettime = time.strftime("%Y%m%d%H%M%S")
# 构建测试报告存放路径和名字
filepath = report_path + f"report{gettime}.html"
# 执行测试,生成测试报告
# 执行加载用例的路径
case_path = "./test_case"
# 模糊匹配
suite = unittest.defaultTestLoader.discover(start_dir=case_path, pattern='C*.py')
with open(filepath, "wb") as f1:
# 使用HTMLTestRunner
# 第一个参数指的生成的测试报告给那个文件写入
# 第一个参数是测试用例的标题
# 第三个参数是对这一次测试的描述
runner = HTMLTestRunner(f1, title=report_title, description=report_desc)
# 执行测试套件
runner.run(suite)