Python框架之UnitTest

unittest 是python 的单元测试框架,unittest 单元测试提供了创建测试用例,测试套件以及批量执行的方案, unittest 在安装pyhton 以后就直接自带了,直接import unittest 就可以使用,测试人员用UnitTest来做自动化测试,即管理和执行用例。

一、UnitTest基本组成

测试人员使用此框架的原因:能够组织多个用例去执行、提供丰富的断言方法、能够生成测试报告。

1、测试发现:从多个py文件中收集并加载测试用例;

2、测试执行:将测试用例按照一定的顺序和条件去执行并生成结果;

3、测试判断:通过断言去判断结果是否正确;

4、测试报告:统计测试进度,通过率,生成报告;

UnitTest的组成部分

1、TestCase:用来写测试用例

2、TestSuite:测试套件,用来组装测试用例,即打包TestCase

3、TestRunner:测试执行,用来执行TestSuite

4、TestLoader:测试加载,对TestSuite功能的补充,用来组装TestCase

5、Fixture:测试夹具,是一种代码结构,前置方法和后置方法

TestCase测试用例

步骤:

(1)导包 unittest

(2)定义测试类,只需要继承unittest.TestCase类就是测试类

(3)书写测试方法,方法名必须以test开头

(4)执行代码

# (1)导包 unittest
import unittest
# (2)定义测试类,只需要继承unittest.TestCase类就是测试类
class TestDemo(unittest.TestCase):# (3)书写测试方法,方法名必须以test开头def test_method1(self):print('测试方法一')def test_method2(self):print('测试方法二')
# (4)执行代码
#  4.1在类名或者方法名后面右键运行。类名后面运行:执行类中所有的测试方法;在方法名后面,只执行当前的测试方法
#  4.2 在主程序中使用unittest.main()来执行
if __name__ == '__main__':unittest.main()

TestSuite和TestRunner

TestSuite(测试套件),用来组装测试用例,将多个测试用例脚本集合在一起。

使用步骤:

  1. 实例化测试套件:suite = unittest.TestSuite()

  2. 添加用例:suite.addTest(ClassName("MethodName"))

    ClassName:为类名;MethodName:为方法名

  3. 添加扩展:suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(ClassName))

  4. 添加扩展:suite.addTest(unittest.makeSuite(测试类名))

    把指定ClassName类中的测试用例全部添加到测试套件中

    案例: 两个用例文件testcase1.py和testcase2.py

    testcase1.py文件中的代码为;

import unittestclass TestDemo1(unittest.TestCase):def test_method1(self):print('测试方法1-1')def test_method2(self):print('测试方法1-2')

testcase2.py文件中的代码为;

# 1、导包
import unittest# 2、定义测试类,继承unittest.TestCase就是测试类
class TestDemo2(unittest.TestCase):# 3、写测试方法,方法中的代码是真正的测试用例代码,方法名必须以test开头def test_method1(self):print('测试方法2-1')def test_method2(self):print('测试方法2-2')

测试套件和执行testsuite_testrunner.py文件中代码为(第一种添加测试套件的方法):

# 1、导包
import unittest
from testcase1 import TestDemo1
# 2、实例化套件对象unittest.TestSuite()
from testcase2 import TestDemo2suite = unittest.TestSuite()
# 3、添加用例方法
# 3.1 套件对象.addTest(测试类名('测试方法名'))
suite.addTest(TestDemo1('test_method1'))
suite.addTest(TestDemo1('test_method2'))
suite.addTest(TestDemo2('test_method1'))
suite.addTest(TestDemo2('test_method2'))
# 4、实例化、执行对象unittest.TextTestRunner()
runner = unittest.TextTestRunner()
# 5、执行 执行对象
runner.run(suite)

执行结果:

image.png

附加:测试套件和执行testsuite_testrunner.py文件中代码为(第二种添加测试套件的方法):

# 1、导包
import unittest
from testcase1 import TestDemo1
# 2、实例化套件对象unittest.TestSuite()
from testcase2 import TestDemo2suite = unittest.TestSuite()
# 3、添加用例方法
# 3.2 添加整个测试类,套件对象.addTest(unittest.makeSuite(测试类名))
suite.addTest(unittest.makeSuite(TestDemo1))
suite.addTest(unittest.makeSuite(TestDemo2))
# 4、实例化、执行对象unittest.TextTestRunner()
runner = unittest.TextTestRunner()去执行()
# 5、执行 执行对象
runner.run(suite)

TestLoader 测试加载

用来加载TestCase到TestSuite中,即加载满足条件的测试用例,并把测试用例封装成测试套件

suite = unittest.TestLoader().discover(test_dir, pattern='test*.py')

自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件

test_dir: 为指定的测试用例的目录

pattern:为查找的.py文件的格式,默认为'test*.py'

import unittestsuite = unittest.TestLoader().discover('E:\pythonProject\pythonUnitTest', 'testcase*.py')
runner = unittest.TextTestRunner()
runner.run(suite)

Fixture:测试夹具

测试夹具是一种代码结构。Fixture控制级别:方法级别、类级别、模块级别(了解即可)。

方法级别(在每个测试用例执行前后都会自动调用,方法名是固定的)

使用方式:

初始化(前置处理):def setUp(self) --> 开始自动执行

销毁(后置处理):def tearDown(self) --> 最后自动执行

类级别(在类中,所有的测试方法执行前后,会自动执行一次,方法名是固定的):

使用方式:

初始化(前置处理):

@classmethoddef setUpClass(cls): 

销毁(后置处理):

@classmethoddef tearDownClass(cls): 

方法名固定的本质是:继承unittest的方法,并且进行覆盖是重写

模块级别 [了解]

运行于整个模块的始末,即:整个模块只会运行一次setUpModule和tearDownModule

使用方式:

初始化(前置处理):def setUpModule()

销毁(后置处理):def tearDownModule()

案例分析:

登录功能的测试用例:

(1)打开浏览器--1次

(2)打开网页,点击登录--每次

(3)输入用户名密码验证码1,点击登录--每次,测试方法1

(4)关闭网页--每次

..................................................................................

(2)打开网页,点击登录--每次

(3)输入用户名密码验证码2,点击登录--每次,测试方法2

(4)关闭网页--每次

..................................................................................

(2)打开网页,点击登录--每次

(3)输入用户名密码验证码3,点击登录--每次,测试方法3

(4)关闭网页--每次

以上案例分析有很多重复的代码,我们可以使用测试夹具优化代码

import unittestclass TestLogin(unittest.TestCase):def setUp(self) -> None:print('2、打开网页,点击登录--每次--前置')def tearDown(self) -> None:print('4、关闭网页--每次--后置')@classmethoddef setUpClass(cls) -> None:print('1、打开浏览器--类前置')@classmethoddef tearDownClass(cls) -> None:print('5、关闭浏览器--类后置')def test_1(self):print('3、输入用户名密码验证码1,点击登录--每次,测试方法1')def test_2(self):print('3、输入用户名密码验证码1,点击登录--每次,测试方法2')def test_3(self):print('3、输入用户名密码验证码1,点击登录--每次,测试方法3')

image.png

二、断言

断言:让程序代替人为判断测试程序执行结果是否符合预期结果的过程

常用的UnitTest断言方法

image.png

对于自动化测试人员来说,重点掌握:

(1)assertEqual(预期结果,实际结果)

判断预期结果和实际结果是否相等,如果相等,用例通过,如果不相等,抛出异常,用例不通过

(2)assertIn(预期结果,实际结果)

判断预期结果是否包含在实际结果中,如果存在,用例通过,如果不存在,抛出异常,用例不通过

import unittestclass TestAssert(unittest.TestCase):def test_equal_1(self):self.assertEqual(10, 10)    # 用例通过def test_assert_2(self):self.assertEqual(10, 20)    # 用例不通过def test_in01(self):self.assertIn('admin', '欢迎admin登录系统!')  # 包含...用例通过def test_in02(self):self.assertIn('addddmin', '欢迎登录系统!')  # 不包含...用例不通过

案例: 工具类中有一个求和的测试方法:

def add(a, b):sum = a+breturn sum

使用断言测试该求和方法是正确:

import unittest
from tools import addclass TestAdd(unittest.TestCase):def test_1(self):self.assertEqual(3, add(1, 2))def test_1(self):self.assertEqual(5, add(3, 2))def test_1(self):self.assertEqual(7, add(4, 3))def test_1(self):self.assertEqual(13, add(8, 5))

三、参数化

通过参数的方式来传递数据,从而实现数据和脚本分离。并且可以实现用例的重复执行。

unittest测试框架,本身不支持参数化,但是可以通过安装unittest扩展插件parameterized来实现。

安装parameterized:pip install parameterized

image.png

参数化实现

导包:from parameterized import parameterized

使用@parameterized.expand装饰器可以为测试函数的参数进行参数化

我们继续对以上的求和方法使用参数化的方式进行测试,代码运行的时候,可以使用多种方式运行,比如:直接右键运行、main方法运行、suite运行等

import unittest
from tools import add
from parameterized import parameterizeddata = [(1, 1, 2), (2, 3, 5), (3, 4, 7), (10, 11, 21)]class TestAdd(unittest.TestCase):@parameterized.expand(data)def test_1(self, a, b, expect):self.assertEqual(expect, add(a, b))if __name__ == '__main__':unittest.main()

扩展:

我们将参数化的测试数据保存在json文件中,如下;

[[1, 1, 2],[2, 3, 5],[3, 4, 7],[10, 11, 21]
]

image.png

读取json文件中的数据:

import jsondef build_add_data():with open('add_data.json',encoding='utf-8')as f:data = json.load(f)return data

image.png

将读取的json文件中的数据当作参数传到测试用例中:

import unittestfrom read_json import build_add_data
from tools import add
from parameterized import parameterizedclass TestAdd(unittest.TestCase):@parameterized.expand(build_add_data)def test_1(self, a, b, expect):self.assertEqual(expect, add(a, b))if __name__ == '__main__':unittest.main()

image.png

以上就是将数据保存在json文件中实现参数化,json文件中的数据复杂的时候,我们可以使用如下方式定义(并且推荐此方法):

image.png

此时读取json文件的方法需要修改为:

def build_add_data():with open('add_data.json', encoding='utf-8')as f:data_list = json.load(f)new_list = []for data in data_list:a = data.get('a')b = data.get('b')expect = data.get('expect')new_list.append((a, b, expect))return new_list

四、生成HTML测试报告

安装:pip install HTMLTestReport

测试报告生成步骤:

(1)导包

(2)封装测试套件

(3)实例化HTMLTestReport对象

report = HTMLTestReport(file_path, [title], [description])

参数说明:

file_path:测试报告文件路径

title:可选参数,为报告标题,如XXX测试报告

description:可选参数,为报告描述信息

(4)执行测试套件report.run(suite)

继续使用上述示例,针对求和的方法进行测试报告的生成

import unittest
from htmltestreport import HTMLTestReport
from testadd_paramterized import TestAdd# 测试套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))# 运行对象
runner = HTMLTestReport('test_add_report.html', '求和运算测试报告', '这是报告的描述!')
runner.run(suite)

运行之后将生成的html报告文件,使用浏览器打开,查看生成的报告,报告中执行失败的用例是故意写错,用来查看执行失败的情况:

image.png

image.png

image.png

使用绝对路径保存测试报告

在实际项目中往往会出现文件找不到的情况,此时需要使用绝对路径。

步骤:

(1)在项目的根目录中创建一个配置文件(app.py或者config.py)

(2)在这个文件中获取项目的目录,在其他代码中拼接起来,完成绝对路径

获取当前文件的绝对路径:abspath = os.path.abspath(__file__)

获取文件路径的目录名称:dirname = os.path.dirname(filepath)

案例:

app.py中的代码内容

import os# 获取当前文件的绝对路径
path1 = os.path.abspath(__file__)
print(path1)# 获取文件路径的目录名称
path2 = os.path.dirname(path1)
print(path2)# 实际中直接合起来写就行
BASE_DIR = os.path.dirname(os.path.abspath(__file__))if __name__ == '__main__':print(BASE_DIR)

运行结果:

image.png

代码中的使用

# 测试套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))# 运行对象
report_path = app.BASE_DIR + "test_add_report.html"  # 报告的路径
runner = HTMLTestReport(report_path, '求和运算测试报告', '这是报告的描述!')
runner.run(suite)

五、测试用例跳过

直接将测试函数标记成跳过@unittest.skip('代码未完成')

根据条件判断测试函数是否跳过@unittest.skipIf(condition, reason)

示例:

import unittestver = 10class TestSkip(unittest.TestCase):@unittest.skip('此用例跳过,这是跳过的原因')def test_1(self):print('测试方法一')@unittest.skipIf(ver >= 10, '迭代版本大于等于10,此用例跳过')def test_2(self):print('测试方法二')def test_3(self):print('测试方法三')if __name__ == '__main__':unittest.main()

image.png

行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/818091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CSS】盒子居中

目录 效果图 代码及其解释 补充解释 效果图 同时实现盒子与文字的居中 代码及其解释 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style type"text/css">#box1{width: 500px;height:…

阿斯达年代记三强争霸开服时间+官网地址+预约下载安装教程分享

阿斯达年代记国际服&#xff0c;游戏分为三个势力&#xff0c;分别是阿斯达、亚高和不罚者&#xff0c;每个玩家都必须选择一个势力&#xff0c;而每个势力每周将会诞生一名势力族长&#xff0c;将会从五名候选人中投票产生&#xff0c;想要进入候选人名单&#xff0c;必须每天…

Netty学习——实战篇2 NIO 群聊系统(简单版) 备份

需求&#xff1a; 1、编写一个NIO群聊系统&#xff0c;实现服务端和客户端之间数据简单通讯(非阻塞) 2、实现多人群聊 3、服务端&#xff1a;可以监测用户上线、离线、并实现消息转发功能。 4、客户端&#xff1a;通过channel可以无阻塞发送消息给其他所有用户&#xff0c;同时…

分类算法(数据挖掘)

目录 1. 逻辑回归&#xff08;Logistic Regression&#xff09; 2. 支持向量机&#xff08;Support Vector Machine, SVM&#xff09; 3. 决策树&#xff08;Decision Tree&#xff09; 4. 随机森林&#xff08;Random Forest&#xff09; 5. K近邻&#xff08;K-Nearest …

Vue3(三):生命周期、路由、自定义hooks

这里终于明白了为什么一直有这个语法报错&#xff0c;就是在提示你哪里错的地方上方注释一行/*eslint-disable*/&#xff0c;之前一直警告这个错误感谢老师&#xff01; 一、vue2和vue3生命周期 还有一个问题就是父组件和子组件哪个先挂载完毕呢&#xff1f;答案是子组件先挂…

Qt---控件的基本属性

文章目录 enabled(控件可用状态)geometry(位置和尺寸)简单恶搞程序 windowIcon(顶层 widget 窗口图标)使用 qrc 机制 windowOpacity(窗口的不透明值)cursor(当鼠标悬停空间上的形状)自定义鼠标图标 toolTip(鼠标悬停时的提示)focusPolicy(控件获取焦点的策略)styleSheet(通过CS…

【Python实践应用】使用Python加载栅格数据

下面的代码实现的是加载伊宁市NDVI数据&#xff0c;首先进行相关的python包的导入&#xff0c;然后定义和读取我们需要加载的数据&#xff0c;这里我们使用的NDVI数据是将伊宁23年的NDVI数据合并成为了一张栅格图像&#xff0c;每个波段表示一年的 NDVI&#xff0c;我们这里显示…

MySQL学习笔记3——条件查询和聚合函数

条件查询和聚合函数 一、条件查询语句二、聚合函数1、SUM&#xff08;&#xff09;2、AVG()、MAX()、MIN()3、COUNT&#xff08;&#xff09; 一、条件查询语句 WHERE 和 HAVING 的区别&#xff1a; WHERE是直接对表中的字段进行限定&#xff0c;来筛选结果&#xff1b;HAVIN…

最新版IntelliJ IDEA 2024.1安装和配置教程 详细图文解说版安装教程

IntelliJ IDEA 2024.1 最新版如何快速入门体验?IntelliJ IDEA 2024.1 安装和配置教程 图文解说版 文章目录 IntelliJ IDEA 2024.1 最新版如何快速入门体验?IntelliJ IDEA 2024.1 安装和配置教程 图文解说版前言 第一步&#xff1a; IntelliJ IDEA 2024.1安装教程第 0 步&…

Java快速入门系列-7(测试与调试)

第七章:测试与调试 第7章:测试与调试7.1 单元测试(JUnit)7.1.1 为什么要进行单元测试7.1.2 JUnit基础7.1.3 断言7.1.4 测试套件7.2 集成测试与系统测试7.2.1 集成测试7.2.2 系统测试7.3 调试技巧与工具7.3.1 断点7.3.2 单步执行7.3.3 变量检查7.3.4 条件断点7.3.5 日志记录…

Playwright已经是目前最好的测试自动化工具了吗?

作者观点&#xff1a;很长时间以来&#xff0c;Selenium是QA工程师寻求测试自动化解决方案的首选测试框架。它能够测试任何浏览器&#xff08;这在IE浏览器的统治时期尤其重要&#xff09;和任何平台。然而&#xff0c;现在看来&#xff0c;那个时代已经过去了。 今天&#xf…

【嵌入式】SD NAND:小身躯蕴含大能量的新型嵌入式存储解决方案

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

如何在Linux通过docker搭建Plik文件系统并实现无公网IP管理内网文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

JNI用法

提示&#xff1a;文章 文章目录 前言一、背景二、 2.1 2.2 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一 背景 之前搞过jni&#xff0c;之前是强哥指导搞的&#xff0c;现在感觉又忘了。 今天照着帖子再搞一次。参考帖子&#xff1a;https://blog.csdn.net/y…

前端 接口返回来的照片太大 加载慢如何解决

现象 解决 1. 添加图片懒加载 背景图懒加载 对背景图懒加载做的解释 和图片懒加载不同&#xff0c;背景图懒加载需要使用 v-lazy:background-image&#xff0c;值设置为背景图片的地址&#xff0c;需要注意的是必须声明容器高度。 <div v-for"img in imageList&quo…

交叉熵损失函数介绍

交叉熵是信息论中的一个重要概念&#xff0c;它的大小表示两个概率分布之间的差异&#xff0c;可以通过最小化交叉熵来得到目标概率分布的近似分布。 为了理解交叉熵&#xff0c;首先要了解下面这几个概念。 自信息 信息论的基本想法是&#xff0c;一个不太可能的事件发生了…

openwrt局域网配置多个IP

在局域网配置过程中&#xff0c;若是DHCP服务器关闭&#xff0c;又忘记了配置的ip&#xff0c;将很难访问到路由器重新进行配置。这种情况可以在路由器出厂时做一个备用ip去避免。 1.配置 以下是备用ip的配置方法&#xff0c;以SKYLAB的SKW99 WIFI模组为例进行说明&#xff1…

如何在树莓派安装Nginx并实现固定公网域名访问本地静态站点

文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx&#xff08;发音为“engine-x”&#xff09;可以将您的树莓派变成一个强大的 Web 服务器&#xff0c;可以用于托管网站或 Web 应用程序。相比其他 Web 服务器&#xff0c;Ngi…

LeetCode 59.螺旋矩阵II

LeetCode 59.螺旋矩阵II 1、题目 力扣题目链接&#xff1a;59. 螺旋矩阵 II - 力扣&#xff08;LeetCode&#xff09; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1…