毛泽东说:“我一生最大的爱好是读书”,“饭可以一日不吃,觉可以一日不睡,书不可以一日不读”。
学习是文明传承之途、人生成长之梯、政党巩固之基、国家兴盛之要。
---谈论学习也不行?
退伍回来10个多月,奈何没有相关的软件测试工作经验和经历,而且毕业四五年没碰过了软件专业了,加之现在疫情的变化无常,报培训班时间不够自由,所以回来边恶补专业知识,边找相关工作。只能是四处碰壁,让我学习的欲望更加强烈。
今天也恰巧看到CSDN话题挑战赛第2期中的《学习笔记》这个参赛话题很符合我,正好把我近期学习的(四)自动化测试-unittest框架简单总结一下,方便自己以后找出来看看。
参赛话题:学习笔记
目 录
一、前期脚本问题
1、测试用例过多,只能单一执行,或者导包执行。
2、断言方式简单且不实用,日志只能体现在控制台输出,无法体现在报告中。
3、无法体现测试报告中的效果:测试用例数量、执行数量、通过数量、失败数量以及失败原因。
二、融入unittest框架
不仅仅是代码级别的功能测试、逻辑覆盖
1、unittest框架好处
(1)提供用例组织与执行
(2)提供丰富的断言方法
(3)提供丰富的日志和报告(HTML格式更直观展示)
2、unittest框架工作原理
(1)Fixture(固定件)
TestCase:测试用例、脚本
TestSuite:测试集合、套件、文件夹、统一管理多条测试用例
TestRunner:测试运行器
TestLoader:测试用例加载器
TestRusult:测试结果、字典类型
(2)单元测试代码段
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author:bigbear
# datetime:2022/9/3 16:39
# software: PyCharm
"""
单元测试:
测试对象:类中的方法(函数)
"""
class MyMath:
"""定义运算函数:实现加减乘除算法"""
@staticmethod
def add(a, b):
"""加法"""
# 测试问题:若a是字符串,b是整型,应该是字符串拼接运算
if isinstance(a, str) and isinstance(b, int):
b = str(b)
return a + b
else:
return a + b
@staticmethod
def subtract(a, b):
"""减法"""
return a - b
@staticmethod
def multiply(a, b):
"""乘法"""
return a * b
@staticmethod
def divide(a, b):
"""除法"""
if b == 0:
return "除数不能是0,小学生都知道的啊"
else:
return a / b
if __name__ == '__main__':
"""单元测试-代码功能验证"""
mm = MyMath()
# 实现第一条加法测试用例
actual_value = mm.add(1, 1)
expect_value = 2
if actual_value == expect_value:
print("加法功能实现正确")
# 实现第二条加法测试用例:can only concatenate str (not "int") to str
try:
actual_value = mm.add("a", 1)
expect_value = "无法运算"
if actual_value == expect_value:
print("加法功能实现正确")
except Exception as e:
print(f"加法功能实现正确:{e}")
# 实现第三条加法测试用例
try:
actual_value = mm.add("a", "b")
expect_value = "ab"
if actual_value == expect_value:
print("加法功能实现正确")
except Exception as e:
print(f"加法功能实现正确:{e}")
三、unittest框架拆分介绍
1、导入unittest包
import unittest
2、创建测试用例类
继承单元测试框架的单元测试用例的类unittest.TestCase
class MyMathUnittest(unittest.TestCase):
"""继承单元测试框架的单元测试用例类"""
3、测试用例类中的五种特殊方法(包含使用场景及执行顺序)
setUp()、test_xxx()、tearDown()执行顺序与位置无关,且每执行一条测试用例,setUp()和tearDown()都会执行一次(无论该测试用例是否通过)。
@classmethod注解的方法是类方法,不用创建对象也可以用的方法,在对象进入内存之前就已经存在的方法,随着类一起进内存。
(1)setUp() # 初始化、环境搭建
(2)test_xxx() # 测试用例方法、步骤
(3)tearDown() # 还原测试用例环境
(4)@classmethod-setUpClass() # 对当前测试用例类的所有测试用例进行初始化,只在类执行开始执行一次
(5)@classmethod-tearDownClass() # 对当前测试用例类的所有测试用例资源进行释放,只在类执行结束执行一次
import unittest
# from importlib import import_module
from my_math import MyMath
class MyMathUnittest(unittest.TestCase):
"""继承单元测试框架的单元测试用例类"""
# 注解:给方法指定特殊含义
@classmethod
def setUpClass(cls) -> None:
print("setUpClass方法")
@classmethod
def tearDownClass(cls) -> None:
print("tearDownClass方法")
def setUp(self) -> None:
"""方法名固定、self参数不能少"""
self.mm = MyMath()
print("setUp方法")
def test_add(self):
"""test_是测试用例:加法运算-正向"""
add_value = self.mm.add(1, 1)
# 断言方法,判断预期结果和实际结果是否相等
# AssertionError: 2 != 3 : 预期和实际结果不相等
self.assertEqual(add_value, 2, "预期和实际结果不相等")
print("test_add方法")
def tearDown(self) -> None:
"""方法名固定、self参数不能少"""
print("tearDown方法")
4、创建测试用例
(1)test_开头
import unittest
from my_math import MyMath
class MyMathUnittest(unittest.TestCase):
"""继承单元测试框架的单元测试用例类"""
def test_add(self):
"""test_是测试用例:加法运算-正向"""
print("test_add方法")
def test_add_1(self):
"""test_是测试用例:加法运算-反向"""
add_value = self.mm.add("a", 1)
self.assertNotEqual(add_value, "a1", "预期和实际结果不相等")
print("test_add_0方法")
def test_add_2(self):
"""test_是测试用例:加法运算-正向"""
add_value = self.mm.add("a", "b")
self.assertEqual(add_value, "ab", "预期和实际结果不相等")
print("test_add_1方法")
5、测试用例执行
(1)main()执行方法
unittest.main() # 所有测试用例执行一遍,但无法控制执行顺序(默认按照字母顺序执行)
if __name__ == '__main__':
"""此文件运行时执行"""
# 执行测试用例类中所有的测试用例
unittest.main()
(2)TestSuite()自带加载执行方法
test_suite = unittest.TestSuite() # 创建测试套件对象
test_suite.addTest(类名("用例名")) # 将一条测试用例添加到测试套件,可以多次添加,任意调换顺序即执行顺序
test_suite.addTests([类名("用例名"),...]) # 将可迭代测试集(列表、字典)中的测试用例添加到测试套件,列表中任意调换顺序即执行顺序
test_suite.addTests(map(类名, ["用例名",...])) # 使用map()方法将类应用于用例返回列表
test_suite.run(unittest.TestResult()) # 运行测试套件,并存储测试结果
if __name__ == '__main__':
"""此文件运行时执行"""
# addTest(类名("用例名")):将一条测试用例添加到测试套件,可以多次添加,任意调换顺序即执行顺序
test_suite = unittest.TestSuite()
# 在测试套件中添加一条测试用例
test_suite.addTest(MyMathUnittest("test_add"))
test_result = unittest.TestResult()
test_suite.run(test_result)
print(test_result.__dict__)
if __name__ == '__main__':
"""此文件运行时执行"""
# addTests([类名("用例名"),...]):将可迭代测试集(列表、字典)中的测试用例添加到测试套件,列表中任意调换顺序即执行顺序
test_suites = unittest.TestSuite()
# 在测试套件中添加多条测试用例
test_list = map(MyMathUnittest, ["test_add_2", "test_add_1", "test_add"])
test_suites.addTests(test_list)
test_results = unittest.TestResult()
test_suites.run(test_results)
print(test_results.__dict__)
(3)TestLoader()特定加载方法
test_loader = unittest.TestLoader() # 创建测试用例加载器对象
loader_suite = test_loader.loadTestsFromName("模块名") # 将某模块中的所有测试用例加载到测试套件中
loader_suite = test_loader.loadTestsFromName("模块名.类名") # 将某模块中的某类中的的所有测试用例加载到测试套件中
loader_suite = test_loader.loadTestsFromName(name="类名", module=import_module("模块名")) # 将某模块中的某类中的的所有测试用例加载到测试套件中
loader_suite = test_loader.loadTestsFromName("模块名.类名.测试用例名") # 将某一条测试用例加载到测试套件中
loader_suite = test_loader.loadTestsFromName(name="类名.测试用例名", module=import_module("模块名")) # 将某一条测试用例加载到测试套件中
# __import__(name):通过python解释器导入模块,非通用
loader_suite = test_loader.loadTestsFromModule(__import__("模块名")) # 将某模块中的所有测试用例加载到测试套件中
# importlib.import_module(name):以编程方式导入模块
loader_suite = test_loader.loadTestsFromModule(import_module("模块名")) # 将某模块中的所有测试用例加载到测试套件中
loader_suite = test_loader.discover("./模块目录", "模块名正则表达式.py") # 将指定模块中的所有测试用例一次性加载
if __name__ == '__main__':
"""此文件运行时执行"""
# 加载测试用例到测试套件中
test_loader = unittest.TestLoader()
# loadTestsFromName("模块名"):将某模块中的所有测试用例加载到测试套件中
# loader_suite = test_loader.loadTestsFromName("unittest_frame")
# loadTestsFromName("模块名.类名"):将某模块中的某类中的的所有测试用例加载到测试套件中
# loader_suite = test_loader.loadTests