不拼花哨,只拼实用: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. 重写 setUptearDown 方法,用于初始化和清理测试环境(如果有必要)。
  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 对象收集

TestLoaderunittest 框架提供的加载测试用例的类。

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.mzph.cn/news/115441.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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…