unittest指南——不拼花哨,只拼实用

  • 📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
  • 📢交流讨论:欢迎加入我们一起学习!
  • 📢资源分享:耗时200+小时精选的「软件测试」资料包
  • 📢 最困难的时候,也就是我们离成功不远的时候!

“ Python为开发者提供了内置的单元测试框架 unittest,它是一种强大的工具,能够有效地编写和执行单元测试。unittest 提供了完整的测试结构,支持自动化测试的执行,能够对测试用例进行组织,并且提供了丰富的断言方法。最终,unittest 会生成详细的测试报告,这个框架非常简单且易于使用。”

unittest核心概念

在 unittest 中,有四个核心概念:

  • TestCase(测试用例):每个测试用例实例用于封装一个或多个测试函数。

  • TestSuite(测试套件):这是多个测试用例的集合,用于组织和执行多个测试用例。

  • TestLoader(测试加载器):这是一个用于将测试用例加载到测试套件中的工具。

  • TextTestRunner(测试运行器):这是用于执行测试用例的运行器,负责运行测试并生成结果报告。

  • Fixture(环境管理机制):这是测试用例的环境搭建和销毁部分,包括前置条件和后置条件。

在这里插入图片描述

unittest的工作流程

  1. 编写继承自 unittest.TestCase 的测试用例类,其中每个测试函数都是一个独立的测试用例。
  2. 使用 TestLoader 加载测试用例,并将它们组织成 TestSuite 对象。
  3. 使用 TestRunner 运行 TestSuite 中的测试用例,并输出测试结果。

使用unittest初级指南

  1. 导入 unittest 模块以及被测试的文件或类。
  2. 创建一个测试类,并继承 unittest.TestCase,所有自定义的单元测试类都要继承它,作为基类。
  3. 重写 setUp 和 tearDown 方法,用于初始化和清理测试环境(如果有必要)。
  4. 定义测试函数,函数名以 test_ 开头,这样才能被识别并执行。
  5. 在测试函数中使用断言来判断测试结果是否符合预期。
  6. 调用 unittest.main() 方法运行测试用例,按照函数名的排序执行测试。

以下是一个简单的例子:

import unittestdef login(username, password):if username == 'kira' and password == '123':res = {"code": 200, "msg": "登录成功"}return resreturn {"code": 400, "msg": "登录失败"}class TestLogin(unittest.TestCase):def test_login_success(self):"""测试登录成功"""test_data = {"username": "kira", "password": "test"}expect_data = {"code": 200, "msg": "登录成功"}res = login(**test_data)self.assertEqual(res, expect_data)def test_login_error_with_error_password(self):"""账号正确,密码错误,登录失败"""test_data = {"username": "kira", "password": "12345"}expect_data = {"code": 400, "msg": "登录失败"}res = login(**test_data)self.assertEqual(res, expect_data)# 更多测试函数类似...if __name__ == '__main__':unittest.main()

以上是一个简单的测试用例,包含了两个测试函数。运行脚本将输出测试结果。

unittest核心概念

测试脚手架

测试脚手架 是测试用例的前置条件和后置条件,确保测试环境的初始化和清理,从而保证测试的准确性和可靠性。

import unittestclass MyTestCase(unittest.TestCase):@classmethoddef setUpClass(cls):# 类级别的前置条件设置,整个类运行最先只执行一次print("setUpClass")@classmethoddef tearDownClass(cls):# 类级别的后置条件清理,整个类运行最后结束执行一次print("tearDownClass")def setUp(self):# 测试方法级别的前置条件设置,所有测试方法运行前都执行一次print("setUp")def tearDown(self):# 测试方法级别的后置条件清理,所有测试方法运行结束都执行一次print("tearDown")def test_example(self):# 测试用例print("test_example")if __name__ == "__main__":unittest.main()
  1. setUp():每个测试方法运行前执行,用于测试前置的初始化工作。
  2. tearDown():每个测试方法结束后执行,用于测试后的清理工作。
  3. setUpClass():所有的测试方法运行前执行,用于单元测试类运行前的准备工作。使用 @classmethod 装饰器装饰,整个测试类运行过程中只会执行一次。
  4. tearDownClass():所有的测试方法结束后执行,用于单元测试类运行后的清理工作。使用 @classmethod 装饰器装饰,整个测试类运行过程中只会执行一次。

测试用例

测试用例 是最小的测试单元,用于检测特定的输入集合的特定的返回值。unittest 提供了 TestCase 基类,所有的测试类都需要继承该基类,而在该类下的函数如果以 test_ 开头,则被标识为测试函数:

class MyTestCase(unittest.TestCase):def test_addition(self):result = 2 + 3self.assertEqual(result, 5)  # 使用断言方法验证结果是否相等def test_subtraction(self):result = 5 - 3self.assertTrue(result == 2)  # 使用断言方法验证结果是否为True# 更多测试用例函数...

断言方法

以下是常用的断言方法:

  • assertEqual(a, b, msg=None):验证 a 等于 b。

  • assertNotEqual(a, b):验证 a 不等于 b。

  • assertTrue(x):验证 x 是否为 True。

  • assertFalse(x):验证 x 是否为 False。

  • assertIs(a, b):验证 a 是否是 b。

  • assertIsNot(a, b):验证 a 是否不是 b。

  • assertIsNone(x):验证 x 是否为 None。

  • assertIsNotNone(x):验证 x 是否不为 None。

  • assertIn(a, b):验证 a 是否在 b 中。

  • assertNotIn(a, b):验证 a 是否不在 b 中。

  • assertIsInstance(a, b):验证 a 是否是 b 类型的实例。

  • assertNotIsInstance(a, b):验证 a 是否不是 b 类型的实例。

可以使用这些方法进行断言,也可以直接使用原生的assert来断言,如果断言失败,测试用例会被定义为执行失败。

忽略特定测试方法

unittest 提供了一些方法来跳过特定的测试用例:

  • @unittest.skip(reason):强制跳过,reason 是跳过的原因。

  • @unittest.skipIf(condition, reason):当 condition 为 True 时跳过。

  • @unittest.skipUnless(condition, reason):当 condition 为 False 时跳过。

  • @unittest.expectedFailure:如果测试失败,这个测试用例不会计入失败的统计。

  • 使用实例方法:self.skipTest() 使用和上述类似。

import sys
import unittestclass Test1(unittest.TestCase):@unittest.expectedFailure  # 即使失败也会被计为成功的用例def test_1(self):assert 1 + 1 == 3@unittest.skip('无条件跳过')  # 不管什么情况都会进行跳过def test_2(self):print("2+2...", 4)@unittest.skipIf(sys.platform == "win32", "跳过")  # 如果系统平台为 Windows 则跳过def test_3(self):print("3+3...", 6)@unittest.skipUnless(sys.platform == "win32", "跳过")  # 除非系统平台为 Windows,否则跳过def test_4(self):print("4+4...", 8)def test_5(self):self.skipTest("跳过")print("5+5...", 10)if __name__ == "__main__":unittest.main(verbosity=2)

测试套件

测试套件用于收集和组织多个测试用例,便于集中执行。

  1. 通过 unittest.main() 方法直接加载单元测试的测试模块,这是一种简单的加载方式。所有测试用例的执行顺序按照方法名的字符串表示的 ASCII 码升序排序,通过命名时使用 test_01_xxx 来指定执行顺序。

  2. 将所有的单元测试用例 TestCase 加载到测试套件 Test Suite 集合中,然后一次性加载所有测试对象。

通过 TestSuite 对象收集

此方式适用于需要自定义组合特定测试用例的情况。

import unittestclass MyTestCase(unittest.TestCase):def test_addition(self):result = 2 + 3self.assertEqual(result, 5)def suite():suite = unittest.TestSuite()suite.addTest(MyTestCase('test_addition'))return suiteif __name__ == '__main__':runner = unittest.TextTestRunner()runner.run(suite())

通过 TestLoader 对象收集

TestLoader 是 unittest 框架提供的加载测试用例的类。

import unittestif __name__ == '__main__':loader = unittest.defaultTestLoader# 自动加载当前模块中所有以 'test_' 开头的测试用例函数suite = loader.loadTestsFromModule(__name__)runner = unittest.TextTestRunner()runner.run(suite)
import unittestclass MyTestCase(unittest.TestCase):def test_addition(self):result = 2 + 3self.assertEqual(result, 5)if __name__ == '__main__':loader = unittest.defaultTestLoader# 自动加载 MyTestCase 类中的所有测试用例suite = loader.loadTestsFromTestCase(MyTestCase)runner = unittest.TextTestRunner()runner.run(suite)
import unittestif __name__ == '__main__':loader = unittest.defaultTestLoader# 自动加载指定名称的测试用例suite = loader.loadTestsFromName('module.MyTestCase.test_addition')runner = unittest.TextTestRunner()runner.run(suite)
import unittestif __name__ == '__main__':loader = unittest.defaultTestLoader# 自动发现并加载指定目录中的测试用例模块suite = loader.discover(start_dir='test_directory', pattern='test_*.py', top_level_dir=None)runner = unittest.TextTestRunner()runner.run(suite)

测试运行器

测试运行器是用于执行和输出测试结果的组件。常用的运行器有:

  • unittest.TextTestRunner:这是 unittest 框架中默认的测试运行器,会在命令行输出测试结果。通过调用 run() 方法运行测试套件,并将测试结果打印到控制台。
import unittestif __name__ == '__main__':loader = unittest.defaultTestLoadersuite = loader.discover(start_dir='tests', pattern='test_*.py')runner = unittest.TextTestRunner()result = runner.run(suite)
  • HTMLTestRunner:这是一个第三方库,能够生成漂亮的 HTML 测试报告,需要进行安装。你可以通过搜索获取相关文件进行安装。
import unittest
from HTMLTestRunner import HTMLTestRunnerif __name__ == '__main__':loader = unittest.defaultTestLoadersuite = loader.discover(start_dir='tests', pattern='test_*.py')with open('test_report.html', 'wb') as report_file:runner = HTMLTestRunner(stream=report_file, title='Test Report', description='Test Results')result = runner.run(suite)
  • XMLTestRunner:这是另一个第三方库,用于生成 XML 格式的测试报告。
import unittest
from xmlrunner import XMLTestRunnerif __name__ == '__main__':loader = unittest.defaultTestLoadersuite = loader.discover(start_dir='tests', pattern='test_*.py')with open('test_report.xml', 'wb') as report_file:runner = XMLTestRunner(output=report_file)result = runner.run(suite)

你也可以自定义测试运行器。继承 unittest.TestRunner 类并实现 run() 方法,以创建自己的测试运行器。

import unittestclass MyTestRunner(unittest.TextTestRunner):def run(self, test):print("Running tests with MyTestRunner")result = super().run(test)return resultif __name__ == '__main__':loader = unittest.defaultTestLoadersuite = loader.discover(start_dir='tests', pattern='test_*.py')runner = MyTestRunner()result = runner.run(suite)

通常使用 HTMLTestRunner 即可满足需求,它非常易用。

实战一个测试案例

假设有一个测试函数 login:

# login.py
def login(username, password):"""模拟登录校验"""if username == 'kira' and password == '123456':return {"code": 0, "msg": "登录成功"}else:return {"code": 1, "msg": "账号或密码不正确"}

设计用例

根据函数的参数和逻辑,设计如下用例:

编写测试用例并运行

import unittest
from login import loginclass TestLogin(unittest.TestCase):def test_login_correct(self):"""测试账号密码正确"""test_data = {"username": "kira", "password": "123456"}expect_data = {"code": 0, "msg": "登录成功"}res = login(**test_data)self.assertEqual(res, expect_data)def test_login_wrong_password(self):"""测试账号正确密码不正确"""test_data = {"username": "kira", "password": "123"}expect_data = {"code": 1, "msg": "账号或密码不正确"}res = login(**test_data)self.assertEqual(res, expect_data)def test_login_wrong_username(self):"""测试账号错误密码正确"""test_data = {"username": "kir", "password": "123456"}expect_data = {"code": 1, "msg": "账号或密码不正确"}res = login(**test_data)self.assertEqual(res, expect_data)if __name__ == '__main__':unittest.main()

这是一个简单的测试用例,包含了三个测试函数。运行测试用例后,会输出测试结果,看完是否觉得unittest非常简单易用。ner.run(suite)

最后的分享

如果你想学习自动化测试,那么下面这套视频应该会帮到你很多

如何逼自己1个月学完自动化测试,学完即就业,小白也能信手拈来,拿走不谢,允许白嫖....

最后我这里给你们分享一下我所积累和整理的一些文档和学习资料,有需要直接领取就可以了!


以上内容,对于软件测试的朋友来说应该是最全面最完整的备战仓库了,为了更好地整理每个模块,我也参考了很多网上的优质博文和项目,力求不漏掉每一个知识点,很多朋友靠着这些内容进行复习,拿到了BATJ等大厂的offer,这个仓库也已经帮助了很多的软件测试的学习者,希望也能帮助到你。

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

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

相关文章

代码随想录算法训练营第五十三天|1143.最长公共子序列 1035.不相交的线 53. 最大子序和

文档讲解:代码随想录 视频讲解:代码随想录B站账号 状态:看了视频题解和文章解析后做出来了 1143.最长公共子序列 class Solution:def longestCommonSubsequence(self, text1: str, text2: str) -> int:dp [[0] * (len(text2) 1) for _ i…

基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码

基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于法医调查优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神…

windows11上安装WSL

Windows电脑上要配置linux(这里指ubuntu)开发环境,主要有三种方式: 1)在windows上装个虚拟机(比如vmware)。缺点是vmware加载ubuntu后系统会变慢很多,而且需要通过samba来实现window…

计算机组成原理。3-408

1.动态存储和静态存储 2.双端口RAM 注意:cpu通过地址线和数据线读写数据时,不能同时写,但可以同时读,也不能一边读一边写。 3.多体并行存储器 分为高位存储和低位存储 小结 4.磁盘存储器的组成 5.磁盘的性能指标 磁盘读写寻道…

Vue中Slot的使用指南

目录 前言 什么是slot? 单个slot的使用 具名slot的使用 作用域插槽 总结 前言 在Vue中,slot是一种非常强大和灵活的功能,它允许你在组件模板中预留出一个或多个"插槽",然后在使用这个组件的时候动态地填充内容。这…

TSINGSEE青犀智能分析网关道路积水识别AI算法方案

在各处的街道、路口等区域,及时发现道路积水问题,可以大大减少城市管理部门压力,及时处理,减少交通事故与人员摔倒事故。通过道路积水AI算法,能有效提高城市管理部门效率,优化城市管理方式。 那么&#xff…

【Web】PhpBypassTrick相关例题wp

目录 ①[NSSCTF 2022 Spring Recruit]babyphp ②[鹤城杯 2021]Middle magic ③[WUSTCTF 2020]朴实无华 ④[SWPUCTF 2022 新生赛]funny_php 明天中期考,先整理些小知识点冷静一下 ①[NSSCTF 2022 Spring Recruit]babyphp payload: a[]1&b1[]1&b2[]2&…

NLP的使用

参考: Apache openNLP 简介 - 链滴 (ld246.com) opennlp 模型下载地址:Index of /apache/opennlp/models/ud-models-1.0/ (tencent.com) OpenNLP是一个流行的开源自然语言处理工具包,它提供了一系列的NLP模型和算法。然而,Open…

【模拟开关CH440R】2022-1-20

资料模拟开关CH440芯片手册 - 百度文库 ch440R回来了,导通usb设备没问题,降压不影响。但是我发现个严重的问题,我的电路是直接通过4067控制ch440r接地,低电平,使能三个线路连一起的,邮箱的图您看看&#xf…

N-134基于java实现捕鱼达人游戏

开发工具eclipse,jdk1.8 文档截图&#xff1a; package com.qd.fish;import java.awt.Graphics; import java.io.File; import java.util.ArrayList; import java.util.List;import javax.imageio.ImageIO;public class Fishes {//定义一个集合来管理鱼List<Fish> fish…

五种多目标优化算法(NSDBO、NSGA3、MOGWO、NSWOA、MOPSO)求解微电网多目标优化调度(MATLAB代码)

一、多目标优化算法简介 &#xff08;1&#xff09;非支配排序的蜣螂优化算法NSDBO 多目标应用&#xff1a;基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度&#xff08;MATLAB&#xff09;-CSDN博客 &#xff08;2&#xff09;NSGA3 NSGA-III求解微电网多目标…

应用场景丨社区燃气管网监测系统建设

燃气作为现代社会的重要能源&#xff0c;燃气被广泛应用于居民生活、工业生产、商业服务等领域。然而&#xff0c;燃气泄漏事故时有发生&#xff0c;不仅给人们的生命财产安全带来严重威胁&#xff0c;也给燃气行业的发展带来不良影响。因此&#xff0c;对于燃气管道的监测和管…

给虚拟机配置静态id地址

1.令人头大的原因 当连接虚拟机的时候 地址不一会就改变&#xff0c;每次都要重新输入 2.配置虚拟机静态id地址 打开命令窗口执行 : vim /etc/sysconfig/network-scripts/ifcfg-ens33 按下面操作修改 查看自己子网掩码 3.重启网络 命令行输入 systemctl restart netwo…

【C语言】函数(四):函数递归与迭代,二者有什么区别

目录 前言递归定义递归的两个必要条件接受一个整型值&#xff08;无符号&#xff09;&#xff0c;按照顺序打印它的每一位使用函数不允许创建临时变量&#xff0c;求字符串“abcd”的长度求n的阶乘求第n个斐波那契数 迭代总结递归与迭代的主要区别用法不同结构不同时间开销不同…

毛利率创历史新高,三季度的小米拿出“新王牌”?

近日&#xff0c;小米正式发布了今年三季度的财报。财报数据显示&#xff0c;小米第三季度经调整净利润为59.9亿元人民币&#xff0c;同比增长182.9%&#xff0c;远超市场预期的48亿元。这其中&#xff0c;手机业务作为小米的基本盘一直是市场的关注焦点。今年三季度&#xff0…

vue3的基本使用(超详细)

一、初识vue3 1.vue3简介 2020年9月18日&#xff0c;vue3发布3.0版本&#xff0c;代号大海贼时代来临&#xff0c;One Piece特点&#xff1a; 无需构建步骤&#xff0c;渐进式增强静态的 HTML在任何页面中作为 Web Components 嵌入单页应用 (SPA)全栈 / 服务端渲染 (SSR)Jams…

搜索引擎语法

演示自定的Google hacking语法&#xff0c;解释含意以及在渗透过程中的作用 Google hacking site&#xff1a;限制搜索范围为某一网站&#xff0c;例如&#xff1a;site:baidu.com &#xff0c;可以搜索baidu.com 的一些子域名。 inurl&#xff1a;限制关键字出现在网址的某…

【Spring】MyBatis的操作数据库

目录 一&#xff0c;准备工作 1.1 创建工程 1.2 准备数据 1.3 数据库连接字符串 1.4 创建持久层接口UserInfoMapper 1.5 单元测试 二&#xff0c;注解的基础操作 2.1 打印日志 2.2 参数传递 2.3 增&#xff08;Insert&#xff09; 2.4 删&#xff08;Delete&#x…

插件预热 | 且看安全小白如何轻松利用Goby插件快速上分

001 前言 各位师傅们好&#xff0c;首先强调一遍我可没做坏事&#xff0c;我只是想学技术&#xff0c;我有什么坏心思呢 回到正题&#xff0c;作为一个初学者&#xff0c;我想和大家分享一下我是如何利用 Goby 进行刷分的经历。大家都知道&#xff0c;刚开始学习的时候&…

Go 语言中的 Switch 语句详解

switch语句 使用switch语句来选择要执行的多个代码块中的一个。 在Go中的switch语句类似于C、C、Java、JavaScript和PHP中的switch语句。不同之处在于它只执行匹配的case&#xff0c;因此不需要使用break语句。 单一case的switch语法 switch 表达式 { case x:// 代码块 cas…