不拼花哨,只拼实用:unittest指南,干货为王!

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

unittest核心概念

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

  1. TestCase(测试用例):每个测试用例实例用于封装一个或多个测试函数。
  2. TestSuite(测试套件):这是多个测试用例的集合,用于组织和执行多个测试用例。
  3. TestLoader(测试加载器):这是一个用于将测试用例加载到测试套件中的工具。
  4. TextTestRunner(测试运行器):这是用于执行测试用例的运行器,负责运行测试并生成结果报告。
  5. 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": "账号或密码不正确"}

设计用例

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

序号标题测试数据预期结果实际结果
1账号密码正确{"username": "kira", "password": "123456"}{"code": 0, "msg": "登录成功"}
2账号正确密码不正确{"username": "kira", "password": "123"}{"code": 1, "msg": "账号或密码不正确"}
3账号错误密码正确{"username": "kir", "password": "123456"}{"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)

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

在这里插入图片描述

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

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

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

相关文章

接口自动化测试工具大全

在互联网时代,服务端测试已经成为一个重要的产品保障手段,各对此公司实施的方法和技术也不同,本文我们就来讨论一下。 互联网服务端接口自动化是各个公司都需要一部分业务,如何快速高效地完成接口测试呢? 以帮助大家实…

Android 13.0 系统设置 app详情页默认关闭流量数据的开关

1.概述 在13.0的系统产品开发中,移动流量消耗也是关于产品优化的一个方面,由于产品需求需要对app详情页的流量进行管控默认关闭流量开关,不让流量无故流失,所以需要从流量开关分析问题流量打开流程,然后关闭 2.系统设置 app详情页默认关闭流量数据的开关的核心类 package…

redhat配置本地yum源(超详细,超简单)

目录 ​编辑 1、硬件配置 2、配置本地yum源 1、硬件配置 注意这里要使用iso文件,并且要选择启动时连接 2、配置本地yum源 创建本地源文件夹 mkdir -p /mnt/cdrom 挂载镜像文件至指定的目录 mount /dev/cdrom /mnt/cdrom 备份本地源 cp -rf /etc/yum.repos.d…

星途星纪元 ES,用艺术思维表达工程技术

10月8日,星途星纪元ES携手世界级成都爱乐首席乐团、旅德青年钢琴家王超,在成都打造了一场“万物星声”超舒适音乐会视听盛宴。这是星途星纪元首次跨界音乐圈、牵手音乐挚友,共同演绎音乐和汽车的美学协奏曲,开启高端超舒适美学新纪…

如何解决git 发生冲突的场景?

一、是什么 一般情况下,出现分支的场景有如下: 多个分支代码合并到一个分支时多个分支向同一个远端分支推送 具体情况就是,多个分支修改了同一个文件(任何地方)或者多个分支修改了同一个文件的名称 如果两个分支中…

vue项目关闭eslint

vue.config.js 中 设置lintOnSave: false;如果有.eslintrc.js 还需将extends清空 // vue.config.jsmodule.exports {lintOnSave: false } // .eslintrc.js module.exports {extends: [] }

Python树莓派开发

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。关…

道可云元宇宙每日资讯|元宇宙行业产教融合共同体成立仪式举行

道可云元宇宙每日简报(2023年10月23日)讯,今日元宇宙新鲜事有: “数字世界‘元’启未来”元宇宙产业发展圆桌会议在南通举行 10月21日下午,以“数字世界‘元’启未来”为主题的元宇宙产业发展圆桌会议在南通市国际会议…

卷积神经网络CNN学习笔记-卷积计算Conv2D函数的理解

目录 1.全连接层存在的问题2.卷积运算3.填充(padding)3.1填充(padding)的意义 4.步幅(stride)5.三维数据的卷积运算6.结合方块思考7.批处理8.Conv2D函数解析9.conv2d代码9.1 stride19.2 stride2 参考文章 1.全连接层存在的问题 在全连接层中,相邻层的神经元全部连接…

微信小程序阻止返回事件

需求场景 当在一个表单页面 填写了很多数据,或者编辑页面数据发生变动之后,这时候返回上一个页面需要提醒用户是否返回的弹框 实现方法一(ios会存在一定的问题) 在onLoad生命周期里 注册 wx.enableAlertBeforeUnload({message: "您内容已更新,还没保存,确定要退出吗?&…

Socks5代理:数字化时代的技术支柱

随着数字化时代的到来,技术不仅改变了我们的日常生活,还重新定义了商业、通信、娱乐和全球互联。在这一浪潮中,Socks5代理技术崭露头角,成为跨界电商、爬虫数据分析、企业出海和游戏体验的关键推动力。这项技术不仅在实现数字化愿…

vue3+ts父子组件以及单页面刷新的方法

父子组件刷新页面: 父组件定义函数reset,子组件props接收 示例一: 父组件 //ts删减部分: import { deleteCompanyById, findAllCompanys } from /api/company import { usePureFetch } from /nexus/useFetch import type Compa…

CUDA学习笔记(十三) Shared Memory

CUDA SHARED MEMORY shared memory在之前的博文有些介绍,这部分会专门讲解其内容。在global Memory部分,数据对齐和连续是很重要的话题,当使用L1的时候,对齐问题可以忽略,但是非连续的获取内存依然会降低性能。依赖于…

基于Pix4D使用无人机光学影像制作正射影像(DOM)和数字表面模型(DSM) 操作步骤

基于Pix4D使用无人机光学影像制作正射影像(DOM)和数字表面模型(DSM) 操作步骤 0. 前言1.获取无人机光学影像2.DOM和DSM3.操作步骤3.1 初始界面3.2 新建项目3.3查看处理过程报告3.4查看处理进度和成果 4.在ArcMap中打开DSM和DOM 0.…

【X3m】DDR压力测试

Index of /downloads/unittest/ 设置CPU模式和降频温度# 若设备重启需再次配置这两条指令 echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor echo 105000 > /sys/devices/virtual/thermal/thermal_zone0/trip_point_1_temp #1 cpu test ec…

django基于Python的房价预测系统+爬虫+大屏可视化分析

欢迎大家点赞、收藏、关注、评论 文章目录 前言一、项目介绍二、开发环境三、功能需求分析1 数据采集功能设计2数据管理功能设计3爬虫功能需求分析4 数据可视化功能需求分析数据库表的设计 四、核心代码五、效果图六、文章目录 前言 房价是一个国家经济水平的重要体现&#xff…

找不到mfc140u.dll无法继续执行此代码的5个修复方法分享

是使用计算机的过程中,我们经常会遇到各种各样问题,其中丢失“mfc140u dll”(动态链接库)是最常见的一种。DLL文件是一种可在多个程序之间共享的代码库,它可以被应用程序在运行时动态加载和卸载。而“mfc140u dll”则是…

三刷操作系统之一文带你搞懂FreeRTOS——信号量

信号量是操作系统中重要的一部分,信号量一般用来进行资源管理和任务同步,FreeRTOS中信号量又分为二值信号量、计数型信号量、互斥信号量和递归互斥信号量。不同的信号量其应用场景不同。 1.信号量简介 信号量常常用于控制对共享资源的访问和任务同步。举一个很常见的例子,…

熟练使用 Redis 的五大数据结构:Java 实战教程

入门 入门阶段主要记住 Redis 的命令,熟练使用 Redis 的 5 大数据结构就可以了。 如果没有 Redis 环境,可以直接通过这个网址https://try.redis.io/,很赞,它会给你模拟一个在线的环境可供你尽情使用! 熟练使用Redis的…

C#数据结构--数组和ArrayList

目录 本章目录: 2.1 数组基本概念 2.1.1 数组的声明和初始化 2.1.2 数组元素的设置和存取访问 2.1.4 多维数组 2.1.5 参数数组 2.2ArrayList 类 2.2.1ArrayList 类的成员 2.2.2 应用 ArrayList 类 数组和ArrayList之间的区别以及使用的场景 数组&#xf…