做养生网站需要证件吗,wordpress搬到谷歌服务器,游戏交易类网站seo怎么做,如何在服务器上搭建网站单元测试自动化
所谓的单元测试(Unit Test)是根据特定的输入数据#xff0c;针对程序代码中的最小实体单元的输入输出的正确性进行验证测试的过程。所谓的最小实体单元就是组织项目代码的最基本代码结构#xff1a;函数#xff0c;类#xff0c;模块等。在Python中比较知名…单元测试自动化
所谓的单元测试(Unit Test)是根据特定的输入数据针对程序代码中的最小实体单元的输入输出的正确性进行验证测试的过程。所谓的最小实体单元就是组织项目代码的最基本代码结构函数类模块等。在Python中比较知名的单元测试模块 unittest pytest doctest nose 测试用例
所谓的测试用例(Test Case)就是执行测试的依据和记录把测试应用程序的操作步骤用文档的形式描述出来的一份文档。文档的格式可以是Excel、markdown、html、xmind网页。
一份合格的测试用例有利于测试人员理清测试思路确保需要测试的功能周全没有遗漏方便测试工作的开展和评估测试工作量同时还可以便于测试人员记录测试数据和测试工作进度为后续的回归测试提供样本参考提升测试效率以及后续测试工作的交接。
那么一份合格的测试用例长什么样子或有什么内容呢
一份合格的测试用例应该包含测试时间、测试人员、测试模块名、功能点名称、用例ID、用例说明测试目的、前置条件、输入数据、预期结果、测试结果输出结果、实际结果等。注意加粗内容为必备的测试用例八要素。
参考文档 在实际工作中因为缺陷报告与测试用例作用相似因此有时候会合并一起或只选择其中一种。
设计方法
那么在工作中我们一般都应该编写测试用例或者应该怎么设计测试用例来完成我们的测试工作呢实际上在工作中测试人员都是基于测试用例的7种基本设计方法来设计与编写测试用例的 等价类划分法根据输入数据的有效性与无效性设计测试用例。 边界值分析法对等价类划分法的一个补充从等价类的边缘值临界点去寻找错误基于这些错误来设计测试用例。 判定表法把输入数据的各种可能情况进行组合罗列成一个判断表以判断表来设计测试用例。 因果图法用图解的方式表示输入数据的各种组合关系以此写出判定表从而设计相应的测试用例。 正交表法基于正交表来设计测试用例。 场景法基于流程图展示业务流程或功能的调用流程对流程图的走向路径设计测试用例。 错误推测法基于经验和直觉找出程序中认为可能出现的错误来设计测试用例。
一般在工作中我们比较常用的是等价类划分法与判定表法。
等价类划分法
等价类划分法就是按照测试要求把具有共同特征的测试数据划分为2类有效等价类和无效等价类把测试数据进行分类以后设计测试用例。 有效等价类就是符合程序使用要求或调用代码要求的能正确使用程序或调用代码的一类数据。 无效等价类就是不符合程序使用要求或调用代码要求的会导致程序出现异常或结果不正确的一类数据。
使用等价类划分法可以让我们设计的测试工作更加科学有依据避免出现穷举测试的情况减少测试用例的数量。
例如注册功能中用户名的测试用例如果功能需求中要求用户名必须长度为3-11个长度的字符。
系统模块功能点用例ID测试目的前置条件输入预期结果会员模块用户注册01验证用户名打开用户注册页面abc正确会员模块用户注册02验证用户名打开用户注册页面abdefgthssaaaaa错误 判定表法
判定表是分析和表达多逻辑条件下执行不同操作的情况的工具。而软件测试中的判定表法就是把输入数据的各种可能情况进行组合罗列成一个判断表格以判断表来设计测试用例。
判定表的表结构一般有如下2种横向判断表与纵向判定表。
横向判断表
条件桩条件项动作桩动作项
纵向判定表
条件桩动作桩条件项动作项 例子测试一个功能是否能修改文件。
如果使用纵向判定表条件1是否有权限条件2是否存在结果1可以修改结果2不能修改√√√✖√✖✖√✖√✖√✖✖✖√ 如果使用横向判断表条件桩是否有权限✔✔✖✖条件桩是否存在✔✖✔✖动作桩可以修改✔✖✖✖动作桩不能修改✖✔✔✔ 单元测试框架-Unittest
Unittest是Python开发中常用于单元测试的内置框架免安装使用简单方便其设计的灵感来源于Java的单元测试框架-Junit。
Unittest具备完整的测试结构支持自动化测试的执行对测试用例进行组织并且提供了丰富的断言方法还提供生成测试报告。
官方文档unittest --- 单元测试框架 — Python 3.11.5 文档
import unittest
print(dir(unittest))
上面的代码中我们就引入了Unittest模块 同时可以通过打印发现Unittest框架中内置了大量的工具成员。这些工具成员中除了以下5个以外其他的都不怎么常用。 TestCase测试用例 是unittest中最重要的一个类用于编写测试用例类是所有测试用例类的父类实现了测试用例的基本代码。 TestSuite测试套件、测试集 可以把多个TestCase组织、打包集成到一个测试集中一起执行TestSuite可以实现多个测试用例的执行。 TextTestRunner测试运行器 TestSuite本身不具备执行的功能所以使用TextTestRunner执行测试套件和输出测试结果。 TestLoader测试加载器 用于加载测试用例TestCase并生成测试套件TestSuite实现自动从代码中加载大量测试用例到测试套件中。 TestFixture测试脚手架 所谓的测试脚手架就是为了开展一项或多项测试所需要进行的准备工作以及所有相关的清理操作。测试脚手架实际上会在执行一些测试代码之前与之后让我们编写一些初始化和销毁的代码。
快速入门
测试用例-TestCase
前面讲到TestCase就是提供给我们编写测试用例的测试代码的那么怎么编写一个测试用例需要4个步骤即可。 导入unittest模块
import unittest
2.定义测试用例类
import unittest
class 测试用例类名(unittest.TestCase): # 所有的测试用例类都必须直接或者间接继承unittest.TestCase.测试用例pass
3.定义测试用例方法此处的测试用例方法就是上面所说的测试用例设计方法中的一行信息的测试代码
import unittest
class 测试用例类名(unittest.TestCase):测试用例# ....def test_测试方法名(参数): # 测试方法必须以test开头或test_开头pass# ....
4.执行测试用例
unittest.main()
在实际工作中我们肯定是在项目中进行测试代码的编写或单独编写一个测试项目但是我们现在刚开始学习所以我们可以先编写一个例子代码对其进行测试以达到学习的目的。
unittest_01_测试用例的编写.py代码 import unittest# 被测试的代码单元
def add(x,y):return xyclass FuncTest(unittest.TestCase):测试用例def test_01(self):print(add(10, 20))def test_02(self):print(add(hello, world))# def test_03(self):# print(add(hello, 20))# 因为pycharm本身内置了执行unittest的功能所以不适用以下代码也能执行但是终端下或者使用其他的代码编辑器时则需要加上。
if __name__ __main__:unittest.main()
运行结果 测试套件-TestSuite
前面我们将到测试套件主要用于把多个测试用例类打包集成到一个测试集中一起执行。工作中一个项目往往需要编写非常多的测试用例而那么多的测试用例也不可能只编写在一个文件中此时就需要使用测试套件了。2个步骤 通过unittest.TestSuite实例化测试套件对象 suite unittest.TestSuite() 通过addTest方法添加测试用例 添加测试用例方法 # 添加测试用例方法
suite.addtest(测试用例类名(测试用例方法名))
# 批量添加测试用例方法
test_data (测试用例类名(测试用例方法名1), 测试用例类名(测试用例方法名2))
suite.addtests(test_data) 添加测试用例类(一次性添加测试用例的所有test_方法) # 添加测试用例类
suite.addtest(unittest.makeSuite(测试用例类名))
# 批量添加测试用例类
test_data (unittest.makeSuite(测试用例类名1), unittest.makeSuite(测试用例类名2))
suite.addTests(test_data)
unittest_02_测试套件的基本使用.py代码
import unittest
import unittest_01_测试用例的编写 as unittest_01
suite unittest.TestSuite()
# # 添加测试用例方法
# suite.addTest(unittest_01.FuncTest(test_01))
# suite.addTest(unittest_01.FuncTest(test_02))
# # 批量添加测试用例方法
# test_data (unittest_01.FuncTest(test_01), unittest_01.FuncTest(test_02))
# suite.addTests(test_data)
# # 添加测试用例类
# suite.addTest(unittest.makeSuite(unittest_01.FuncTest))
# 批量添加测试用例类
test_data (unittest.makeSuite(unittest_01.FuncTest), unittest.makeSuite(unittest_01.FuncTest))
suite.addTests(test_data) TestSuite的作用仅仅是把多个测试用例打包集成到一块但是并没有提供批量执行测试用例的方法所以我们需要使用TextTestRunner了。
测试运行器-TextTestRunner
前面说过TextTestRunner是用于执行测试用例、测试套件和输出测试结果的。2个步骤 实例化运行器对象 通过run方法执行测试
unittest_03_测试运行器基本使用.py代码
import unittestimport unittest_01_测试用例的编写 as unittest_01suite unittest.TestSuite()# # 添加测试用例方法
# suite.addTest(unittest_01.FuncTest(test_01))
# suite.addTest(unittest_01.FuncTest(test_02))# # 批量添加测试用例方法
# test_data (unittest_01.FuncTest(test_01), unittest_01.FuncTest(test_02))
# suite.addTests(test_data)# # 添加测试用例类
# suite.addTest(unittest.makeSuite(unittest_01.FuncTest))# 批量添加测试用例类
test_data (unittest.makeSuite(unittest_01.FuncTest), unittest.makeSuite(unittest_01.FuncTest))
suite.addTests(test_data)if __name__ __main__:runner unittest.TextTestRunner()runner.run(suite)
运行结果 测试加载器-TestLoader
前面说过用于加载测试用例TestCase并生成测试套件TestSuite实现自动从代码中加载大量测试用例到测试套件中。2个步骤 实例化unittest.TestLoader对象 loader unittest.TestLoader() 使用discover方法自动搜索指定目录下指定文件格式的python模块并把查找到的测试用例组装打包集成到测试组件作为返回值。 loader.discover(目录路径, pattern文件名格式) 注意pattern支持*号表示0到多个字符。
unittest_04_测试加载器基本使用.py代码
import unittest
loader unittest.TestLoader()
# 在当前目录下搜索以unittest开头作为文件名的所有python文件并把文件中的测试用例类打包集成到测试套件中
suite loader.discover(./, patternunittest*.py)if __name__ __main__:runner unittest.TextTestRunner()runner.run(suite)
运行结果 测试脚手架-TestFixture
前面提到测试脚手架会在执行一些测试代码之前与之后让我们编写一些初始化和销毁的代码主要分三个级别 方法级别在方法执行前与执行后都提供自动调用的实例方法 setUp和tearDown 类级别在类执行前与执行后都提供自动调用的类方法不管类中有多少方法只执行一次。 setUpClass和tearDownClass 模块级别在模块执行前与执行后都提供自动调用的函数不管模块中有多少类或方法只执行一次。 setUpModule和tearDownModule 方法级别的脚手架
在测试用例类中提供了2个固定名字的实例方法setUp与tearDown用于完成方法执行前与执行后的操作。
unittest_05测试脚手架方法级别的脚手架.py代码
import unittest# 被测试的代码单元
def add(x,y):return xyclass AddTest(unittest.TestCase):测试用例def setUp(self):print(每个方法执行前都会执行一遍setUp实例方法用于完成通用的前置操作或初始化工作)def tearDown(self):print(每个方法执行后都会执行一遍tearDown实例方法用于完成通用的后置操作或销毁工作)def test_01(self):print(add(10, 20))def test_03(self):print(add(hello, 20))# 因为pycharm本身内置了执行unittest的功能所以不适用以下代码也能执行但是终端下或者使用其他的代码编辑器时则需要加上。
if __name__ __main__:unittest.main()
运行尝试 类级别的脚手架
在测试用例类中提供了2个固定名字的类方法setUpClass与tearDownClass用于完成类执行前与执行后的操作。
unittest_06测试脚手架类级别的脚手架.py代码
import unittest# 被测试的代码单元
def add(x,y):return xyclass AddTest(unittest.TestCase):测试用例classmethoddef setUpClass(cls):print(当前类执行前都会执行一遍setUpClass类方法用于完成通用的前置操作或初始化工作)classmethoddef tearDownClass(cls):print(当前类执行后都会执行一遍tearDownClass类方法用于完成通用的后置操作或销毁工作)def test_01(self):print(add(10, 20))def test_03(self):print(add(hello, 20))# 因为pycharm本身内置了执行unittest的功能所以不适用以下代码也能执行但是终端下或者使用其他的代码编辑器时则需要加上。
if __name__ __main__:unittest.main()
模块级别的脚手架
在测试用例类中提供了2个固定名字的函数setUpModule与tearDownModule用于完成类执行前与执行后的操作。
unittest_07测试脚手架模块级别的脚手架.py代码 import unittestdef setUpModule():print(当前模块执行前都会执行一遍setUpModule函数用于完成通用的前置操作或初始化工作)def tearDownModule():print(当前模块执行前都会执行一遍tearDownModule函数用于完成通用的前置操作或初始化工作)# 被测试的代码单元
def add(x, y):return x yclass AddTest1(unittest.TestCase):测试用例classmethoddef setUpClass(cls):print(当前类执行前都会执行一遍setUpClass类方法用于完成通用的前置操作或初始化工作)classmethoddef tearDownClass(cls):print(当前类执行后都会执行一遍tearDownClass类方法用于完成通用的后置操作或销毁工作)def test_01(self):print(add(10, 20))class AddTest2(unittest.TestCase):测试用例classmethoddef setUpClass(cls):print(当前类执行前都会执行一遍setUp方法用于完成通用的前置操作或初始化工作)classmethoddef tearDownClass(cls):print(当前类执行后都会执行一遍tearDown方法用于完成通用的后置操作或销毁工作)def test_03(self):print(add(hello, 20))# 因为pycharm本身内置了执行unittest的功能所以不适用以下代码也能执行但是终端下或者使用其他的代码编辑器时则需要加上。
if __name__ __main__:unittest.main()
生成HTML格式测试报告(很少使用基本不使用)
使用HTMLTestRunner模块可以直接生成HTML格式的报告。HTMLTestRunner是一个不再维护的第三方的模块通过pip工具安装不了只能下载后手动导入。
HTMLTestRunner官网HTMLTestRunner - tungwaiyips software
HTMLTestRunner下载http://tungwaiyip.info/software/HTMLTestRunner_0_8_2/HTMLTestRunner.py
我就先跳过
断言
断言(assertion)是一种在程序中的判断测试用例执行结果是否符合预期结果的方式所以断言也被称之为“期望”。当程序执行到断言的位置时对应的断言应该为真。若断言不为真时程序会中止执行并给出错误信息。
unittest中常用的断言方法加粗为重要方法
断言方法断言描述assertEqual(arg1, arg2, msgNone)验证arg1arg2不等则failassertNotEqual(arg1, arg2, msgNone)验证arg1 ! arg2, 相等则failassertTrue(expr, msgNone)验证expr是true如果为false则failassertFalse(expr,msgNone)验证expr是false如果为true则failassertIs(arg1, arg2, msgNone)验证arg1、arg2是同一个对象不是则failassertIsNot(arg1, arg2, msgNone)验证arg1、arg2不是同一个对象是则failassertIsNone(expr, msgNone)验证expr是None不是则failassertIsNotNone(expr, msgNone)验证expr不是None是则failassertIn(arg1, arg2, msgNone)验证arg1是arg2的子串不是则failassertNotIn(arg1, arg2, msgNone)验证arg1不是arg2的子串是则failassertIsInstance(obj, cls, msgNone)验证obj是cls的实例不是则failassertNotIsInstance(obj, cls, msgNone)验证obj不是cls的实例是则fail unittest_09_断言.py代码
import unittestdef add(x ,y):return x yclass AddTest(unittest.TestCase):def test_01(self):res add(1,2)# 断言结果是否与预期内容相同# self.assertEqual(res, 3, msg断言失败一般会错误的结果与原因)# self.assertEqual(res, 2, msg断言失败一般会错误的结果与原因)self.assertIn(res, [1, 2], msg断言失败一般会错误的结果与原因)if __name__ __main__:unittest.main()跳过
针对开发中有时候针对不同环境或者不同的时间段不同的代码版本有时候部分测试用例不希望被执行则可以使用跳过。
unittest.skipIf(判断条件表达式, 跳过原因) unittest_10_跳过.py代码
import unittestdef add(x, y):return x yversion (2, 7, 0)class AddTest(unittest.TestCase):def setUp(self):print(setUP执行....)unittest.skipIf(version (3, 5, 0), 版本低于3.5所以不测试test_01)def test_01(self):res add(1, 2)self.assertIn(res, [1, 3], msg断言失败一般会错误的结果与原因)def test_02(self):res add(a, B)self.assertEqual(res, aB, msg断言失败一般会错误的结果与原因)if __name__ __main__:unittest.main()参数化
当需要使用多组不同的测试数据测试同一个方法时可以使用unittest参数化来解决。常用的参数化方法有ddt、paramunittes
pip install parameterized
unittest_11_参数化.py代码
import unittest
from parameterized import parameterizeddef add(x, y):return x yversion (2, 7, 0)class AddTest(unittest.TestCase):def setUp(self):print(setUP执行....)parameterized.expand([(10,20), (a,B), (50, 20)])def test_00(self, x, y):res add(x, y)self.assertIn(res, [1, 30, aB, 70], msg断言失败一般会错误的结果与原因)# def test_01(self):# res add(1, 2)# self.assertIn(res, [1, 3], msg断言失败一般会错误的结果与原因)## def test_02(self):# res add(a, B)# self.assertEqual(res, aB, msg断言失败一般会错误的结果与原因)## def test_03(self):# print(add(a, 20))if __name__ __main__:unittest.main() 数据驱动测试
Data-Driven TestsDDT即数据驱动测试可以实现多个数据对同一个方法进行测试达到数据和测试代码分离目的是为了减少测试用例的数量。
基本安装 pip install ddt 直接传递单个数据
unittest_12参数化基于ddt直接传递数据.py代码
import unittest
from ddt import ddt, datadef add(a,b):return abddt
class AddTest(unittest.TestCase):# # 单次传递一个数据到测试用例方法中# data(100)# data([1,2,3,4])# data({a:1,b:2})# data((1,2,3))# # 多次传递一个数据到测试用例方法中# data(*[a,b,c]) # 字符串# data(*[{a:1}, {a:2}, {a:3}]) # 字典# data(*[[1, 1, 1], [1, 1, 2], [1, 1, 3]])data([1, 1, 1], [1, 1, 2], [1, 1, 3])def test_01(self, a):print(a)if __name__ __main__:unittest.main() unittest_13_参数化-基于ddt解包传递多个数据.py使用unpack装饰器解包数据
import unittest
from ddt import ddt, data, unpackdef add(a, b, c):return a b cddt
class AddTest(unittest.TestCase):data((1,2,3),(1,2,1),(1,3,1),(1,1,3))unpackdef test_01(self,a,b,c):add(a,b,c)if __name__ __main__:unittest.main() 最后
我感觉还是测试岗位相对机会多一点对于我这种普通人开发的话大家需要认真考量自己的实力希望大家也能在秋招之际找到一个好工作