【Python自动化测试】:Unittest单元测试与HTMLTestRunner自动生成测试用例的好帮手

读者大大们好呀!!!☀️☀️☀️


博客头像
🔥 欢迎来到我的博客
👀期待大大的关注哦❗️❗️❗️
🚀欢迎收看我的主页文章➡️寻至善的主页

文章目录

  • 🔥前言
  • 🚀unittest编写测试用例
  • 🚀unittest测试用例执行
  • 🚀unittest常见的断言方法
  • 🚀unittest测试结果分析
  • 🚀unittest测试用例的执行顺序
  • 🚀跨文件组织测试用例
  • 🚀HTMLTestRunner生成测试报告
  • ⭐️⭐️⭐️总结

🔥前言

哲学三问:什么是Unittest?Unittest可以做什么?为什么用Unitest?

1️⃣Python自带的单元测试框架,此外基于Python还有其他的单元测试框架:pytest,doctest,nose等
2️⃣编写规范的测试用例,组织测试用例,生成测试结果
3️⃣自动化编写脚本(自动化测试用例)通常使用单元测试框架来编写,组织和生成测试结果
下面就是实操环节了,尽情期待吧!

🚀unittest编写测试用例

第一步:打开你已经装好的神器:pyCharm,没错就是这个东西:
在这里插入图片描述
第二步:新建一个工程---->unitTest1
在这里插入图片描述
第三步:建立一个简单的被测试文件(包含了加减乘除的函数类)---->count.py

class Count:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def add(self):
        c = self.a + self.b
        return c

    def sub(self):
        d = self.a - self.b
        return d

    def div(self):
        e = self.a * self.b
        return e

    def mul(self):
        e = self.a / self.b
        return e

在这里插入图片描述
第四步:根据被测函数使用unittest编写测试代码创建测试文件----Testcount.py
1️⃣这里记得选Python unit Test创建Python测试文件:
在这里插入图片描述
2️⃣随后会自动生成这些代码:

import unittest


class MyTestCase(unittest.TestCase):
    def test_something(self):
        self.assertEqual(True, False)  # add assertion here


if __name__ == '__main__':
    unittest.main()

在这里插入图片描述
第五步:开始编写构造测试用例函数了:

import unittest
from count import Count


class TestCaseCount(unittest.TestCase):
    def setUp(self) -> None: # 每个测试用例开始前执行
        print("这是执行的测试准备阶段!我要开始测试了!")  # add assertion here

    def test_add1(self):  # 定义测试步骤与断言
        print("我执行的是加法函数测试!")   # 添加该print语句帮助我们了解test_add1何时被执行
        c1 = Count(1, 2)  # 根据Count类生成对象c1,会自动调用Count类里的init方法
        r1 = c1.add()  # r1保存的是实际被测代码的运行结果
        self.assertEqual(r1, 3)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败

    def test_sub2(self):  # 定义测试步骤与断言
        print("我执行的是减法函数测试!")   # 添加该print语句帮助我们了解test_sub2何时被执行
        d1 = Count(2, 1)  # 根据Count类生成对象d1,会自动调用Count类里的init方法
        r2 = d1.sub()  # r2保存的是实际被测代码的运行结果
        self.assertEqual(r2, 1)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败

    def test_div3(self):  # 定义测试步骤与断言
        print("我执行的是乘法函数测试!")   # 添加该print语句帮助我们了解test_div3何时被执行
        e1 = Count(2, 2)  # 根据Count类生成对象e1,会自动调用Count类里的init方法
        r3 = e1.div()  # r3保存的是实际被测代码的运行结果
        self.assertEqual(r3, 4)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败

    def test_mul4(self):  # 定义测试步骤与断言
        print("我执行的是除法函数测试!")   # 添加该print语句帮助我们了解test_mul4何时被执行
        f1 = Count(4, 2)  # 根据Count类生成对象c1,会自动调用Count类里的init方法
        r4 = f1.mul()  # r1保存的是实际被测代码的运行结果
        self.assertEqual(r4, 2)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败
    
    def tearDown(self) -> None:  # 每个测试用例结束后执行
        print("这是执行测试的结束,收拾残局阶段!!")


if __name__ == '__main__':
    unittest.main()

PS:执行Python文件的内部调用与外部调用
在这里插入图片描述

🚀unittest测试用例执行

上面的测试用例函数结构是:
方法名必须是以“test_”打头,然后再是定义测试步骤与断言,断言会在下面讲到。现在是运行截图:
在这里插入图片描述

🚀unittest常见的断言方法

1️⃣assertEqual(a,b):判断a,b是否相等,如果相等,测试通过,如果不相等,测试失败
2️⃣assertNotEqual(a,b):判断a,b是否不相等,如果相等,测试失败

3️⃣assertTrue(x):用于判断bool(x)是否是True,如果不是True,测试失败 与1️⃣等效
4️⃣assertFalse(x):用于判断bool(x)是否是False,如果不是False,测试失败 与2️⃣等效
比如一个函数判断一个数是否是素数便可用3、4的断言方法

5️⃣assertIn(a,b):用于判断a是否在b中,如果a不在b中,则测试失败
6️⃣assertNotIn(a,b)和上个结果相反

🚀unittest测试结果分析

测试结果有三种:
1️⃣测试通过–》 . 一个点表示一个用例通过,上面的图片已经指出,下面着重介绍另外两种
2️⃣测试失败–》
测试的函数方法与预期结果不符合便是测试失败;比如我把加法的方法改一下:

    def add(self):
        c = self.a
        return c

然后再进行测试:
在这里插入图片描述
显示三个用例成功,一个用例失败。
3️⃣测试错误–》
被测试代码或语法原因产生的错误:
现在我把被测试函数的默认属性方法改错:

# def __init__(self, a, b):
    def __int__(self, a, b):
        self.a = a
        self.b = b

执行后直接报错:
在这里插入图片描述

🚀unittest测试用例的执行顺序

测试方法的执行跟编写的顺序无关,而是根据test_后面接的ASCII码的顺序来执行(0-9,A-Z, _, a-z编码越小执行的优先级越高)

当然我们也可以按照自定义的顺序来执行:
不使用unittest的main方法默认顺序执行,而是通过改为使用unittest提供的TestSuit(测试套件)+TestRunner(测试运行器)的方式可以实现自定义顺序执行测试方法
我把下面main方法改一下:

if __name__ == '__main__':
 # unittest.main()   # 调用main()使用的是默认执行顺序
    # 使用test suite+test runner来自定义执行顺序
    # 一、按自定义顺序加载测试方法到测试套件里
    ts = unittest.TestSuite()  # 调用unittest提供的TestSuite类生成对象ts
    ts.addTest(TestCaseCount("test_mul4"))# 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_mul4测试方法
    ts.addTest(TestCaseCount("test_div3"))# 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_div3测试方法
    ts.addTest(TestCaseCount("test_sub2"))# 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_sub2测试方法
    ts.addTest(TestCaseCount("test_add1"))# 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_add1测试方法
    # 二、使用测试运行器执行测试套件里的用例,生成测试结果
    tr = unittest.TextTestRunner()  # 调用unittest提供的TextTestRunner类生成对象tr
    tr.run(ts)  # 调用TextTestRunner里的run方法来执行测试套件ts里的用例执行并生成结果

执行结果如下:
在这里插入图片描述

🚀跨文件组织测试用例

被测功能点肯定不止一个,而是多个,当被测功能点不断扩展,相应的测试代码也会不断的增多,这些测试代码不可能全部写在一个文件里。此时,通常的处理办法:根据所测功能点的不同,将相应的测试代码分散在不同的文件里,然后组织这些分散在不同文件里的代码一起执行。

组织分散在不同文件里的测试代码一起执行的常见办法:
🅰️Test Suite+Test Runner
🅱️discover
下面我将创建一个测试文件testcount2,里面的测试用例为其他测试数,两个runtest测试文件来区分上面🅰️,🅱️两种不同的执行方法
testcount2的文件代码为:

import unittest
from count import Count


class TestCaseCount(unittest.TestCase):
    def setUp(self) -> None: # 每个测试用例开始前执行
        print("这是第二次执行的测试准备阶段!我要开始测试了!")  # add assertion here

    def test_add1(self):  # 定义测试步骤与断言
        print("我执行的是第二次加法函数测试!")   # 添加该print语句帮助我们了解test_add1何时被执行
        c1 = Count(2, 2)  # 根据Count类生成对象c1,会自动调用Count类里的init方法
        r1 = c1.add()  # r1保存的是实际被测代码的运行结果
        self.assertEqual(r1, 4)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败

    def test_sub2(self):  # 定义测试步骤与断言
        print("我执行的是第二次减法函数测试!")   # 添加该print语句帮助我们了解test_sub2何时被执行
        d1 = Count(4, 1)  # 根据Count类生成对象d1,会自动调用Count类里的init方法
        r2 = d1.sub()  # r2保存的是实际被测代码的运行结果
        self.assertEqual(r2, 3)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败

    def test_div3(self):  # 定义测试步骤与断言
        print("我执行的是第二次乘法函数测试!")   # 添加该print语句帮助我们了解test_div3何时被执行
        e1 = Count(1, 2)  # 根据Count类生成对象e1,会自动调用Count类里的init方法
        r3 = e1.div()  # r3保存的是实际被测代码的运行结果
        self.assertEqual(r3, 2)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败

    def test_mul4(self):  # 定义测试步骤与断言
        print("我执行的是第二次除法函数测试!")   # 添加该print语句帮助我们了解test_mul4何时被执行
        f1 = Count(1, 1)  # 根据Count类生成对象c1,会自动调用Count类里的init方法
        r4 = f1.mul()  # r1保存的是实际被测代码的运行结果
        self.assertEqual(r4, 1)  # 将实际结果跟预期结果做等值比较,相等测试通过,不等测试失败

    def tearDown(self) -> None:  # 每个测试用例结束后执行
        print("这是第二次执行测试的结束,收拾残局阶段!!")

if __name__ == '__main__':
    unittest.main()

runtest1的代码为:所使用的是Test Suite+Test Runner方法

import unittest
import testcount
import testcount2

if __name__ == '__main__':
    # unittest.main()   # 调用main()使用的是默认执行顺序
    # 使用test suite+test runner来自定义执行顺序
    # 一、按自定义顺序加载测试方法到测试套件里
    ts = unittest.TestSuite()  # 调用unittest提供的TestSuite类生成对象ts
    ts.addTest(testcount.TestCaseCount("test_mul4"))  # 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_mul4测试方法
    ts.addTest(testcount2.TestCaseCount2("test_mul4"))
    ts.addTest(testcount.TestCaseCount("test_div3")) # 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_div3测试方法
    ts.addTest(testcount2.TestCaseCount2("test_div3"))
    ts.addTest(testcount.TestCaseCount("test_sub2"))  # 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_sub2测试方法
    ts.addTest(testcount2.TestCaseCount2("test_sub2"))
    ts.addTest(testcount.TestCaseCount("test_add1"))  # 调用TestSuite里的addTest方法来加载TestCaseCount类里的test_add1测试方法
    ts.addTest(testcount2.TestCaseCount2("test_add1"))
    # 二、使用测试运行器执行测试套件里的用例,生成测试结果
    tr = unittest.TextTestRunner()  # 调用unittest提供的TextTestRunner类生成对象tr
    tr.run(ts)  # 调用TextTestRunner里的run方法来执行测试套件ts里的用例执行并生成结果

运行结果截图:
在这里插入图片描述

runtest2的代码为:所使用的是discover方法

import unittest

if __name__ == '__main__':
    # unittest.main()
    # 使用discover加载testcount.py和testcount2.py里的用例一起执行
    # 自动发现unitTest1包下的testcount打头的Python文件里的测试方法,将其加载到测试套件ts里
    ts = unittest.defaultTestLoader.discover("./", pattern="testcount*.py")
    # 运行器运行套件用例
    tr =unittest.TextTestRunner()
    tr.run(ts)

运行截图如下:
在这里插入图片描述

🚀HTMLTestRunner生成测试报告

既然我们做的是测试,那么便要实现生成独立的测试报告:这里我们需要用到第三方库HTMLTestRunner.py------>独立生成HTML文件格式的测试文档:
在网上(包括在Python官方文库)找不到HTMLTestRunner相关解释资料。其实HTMLTestRunner是一个第三方的unittest HTML报告库,关于unittest在Python官方文库上很容易找到:然后下载下来放到Python的lib文件下

具体实现代码在runtest2下,代码修改如下:

import unittest
import HTMLTestRunner

if __name__ == '__main__':
    # unittest.main()
    # 使用discover加载testcount.py和testcount2.py里的用例一起执行
    # 自动发现unitTest1包下的testcount打头的Python文件里的测试方法,将其加载到测试套件ts里
    ts = unittest.defaultTestLoader.discover("./", pattern="testcount*.py")
    # 运行器运行套件用例
    # tr =unittest.TextTestRunner()
    # tr.run(ts)
    # 除了可以使用unittest提供的TextTestRunner文本测试运行器来执行用例生成测试结果以外,
    # 还可以使用HTMLTestRunner.py模块提供的HTMLTestRunner类来执行用例生成独立的测试报告
    # 以二进制写的模式打开当前目录下的report.html文件,准备往里面写内容,如果文件不存在则自动创建
    f = open('./report.html', 'wb')
    tr = HTMLTestRunner.HTMLTestRunner(stream=f, title="四则运算测试报告", description="说明信息")
    tr.run(ts)
    f.close()

生成的HTML文件测试报告截图如下:
在这里插入图片描述

⭐️⭐️⭐️总结

test case测试用例unittest提供了TestCase类用来编写测试用例
test suite测试套件unittest提供了TestSuite类用来组装测试用例生成测试用例集合
test runner测试运行器unittest提供了TextTestRunner类用来执行测试用例生成测试结果
test fixture测试固件unittest提供了一系列的固件:setUp,tearDown就是测试固件的一种,用来完成测试前的准备工作和测试后的清理工作。

✈️✈️✈️如果喜欢这篇文章的话

🙏大大们可以动动发财的小手:
👉👉👉 点赞:👍收藏:⭐️评论:✍️👈👈👈

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【408精华知识】Cache类题目解题套路大揭秘

有关Cache的题目,需要理解Cache的工作原理,也即给出一个地址,要知道如何在Cache中寻找或者如何将其从主存中复制入Cache,同时理解Cache中具体是如何存储的,包含三种存储方式,分别是直接映射、全相联映射、组…

clion/pycharm 安装中文

楼主版本 2024.1 mac 操作系统,理论上不同版本和不同操作系统操作应该大同小异 首先找到插件的位置 方式一 1、进入工程,右上角找到设置 2、找到插件(欢迎界面也能找到这个) 方式二 在欢迎界面找到插件 最后 插件商店搜索 l…

矩阵乘法不满足交换律-反证法

假定有2个矩阵A和B A*B 不等于 B*A 手写证明: A*B为 B*A为 由此可以看出,矩阵乘法不满足交换律!!

Python | Leetcode Python题解之第100题相同的树

题目: 题解: class Solution:def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:if not p and not q:return Trueif not p or not q:return Falsequeue1 collections.deque([p])queue2 collections.deque([q])while queue1 and queue2:node…

centos7和centos8安装mysql5.6 5.7 8.0

https://dev.mysql.com/downloads/repo/yum/ 注意构造下http://repo.mysql.com/mysql-community-release-el*-*.noarch.rpm 【以centos7为例】 安装mysql5.6 wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm rpm -ivh mysql-community-release-el7-5…

初识Qt:从Hello world到对象树的深度解析

Qt中的对象树深度解析 Hello world1.图形化界面创建命令行式创建在栈上创建在堆上创建为什么传文本需要QString,std::string不行吗?那为什么要传入this指针?为什么new后不用显示调用delete函数呢,不会造成内存泄漏问题吗&#xff…

国产操作系统上使用SQLynx连接数据库 _ 统信 _ 麒麟 _ 中科方德

原文链接:国产操作系统上使用SQLynx连接数据库 | 统信 | 麒麟 | 中科方德 Hello,大家好啊!今天我们将探讨如何在国产操作系统上使用SQLynx。这是一款功能强大的数据库管理工具,可以帮助用户高效地管理和操作数据库。本文将详细介绍…

2024 电工杯高校数学建模竞赛(A题)数学建模完整思路+完整代码全解全析

你是否在寻找数学建模比赛的突破点?数学建模进阶思路! 作为经验丰富的数学建模团队,我们将为你带来2024电工杯数学建模竞赛(B题)的全面解析。这个解决方案包不仅包括完整的代码实现,还有详尽的建模过程和解…

Docker搭建mysql性能测试环境

OpenEuler使用Docker搭建mysql性能测试环境 一、安装Docker二、docker安装mysql三、测试mysql连接 一、安装Docker 建立源文件vim /etc/yum.repos.d/docker-ce.repo增加内容[docker-ce-stable] nameDocker CE Stable - $basearch baseurlhttps://repo.huaweicloud.com/docker…

NLP(18)--大模型发展(2)

前言 仅记录学习过程,有问题欢迎讨论 Transformer结构: LLM的结构变化: Muti-head 共享: Q继续切割为muti-head,但是K,V少切,比如切为2个,然后复制到n个muti-head减少参数量,加速训练 atte…

STM32-串口通信波特率计算以及寄存器的配置详解

您好,我们一些喜欢嵌入式的朋友一起建立的一个技术交流平台,本着大家一起互相学习的心态而建立,不太成熟,希望志同道合的朋友一起来,抱歉打扰您了QQ群372991598 串口通信基本原理 处理器与外部设备通信的两种方式 并行…

flume使用实例

1、监听端口a1.sources.r1.type netcat 配置文件nc-flume-console.conf # Name the components on this agent a1 表示jvm进程名 a1.sources r1 a1.sinks k1 a1.channels c1 # Describe/configure the source a1.sources.r1.type netcat a1.sources.r1.bind node…

《王者荣耀》4月狂揽2.34亿美元 单日流水1亿美元 全球销量第二

易采游戏网5月24日消息,在刚刚过去的四月,全球手游市场迎来了一场收益的盛宴,其中《王者荣耀》以其惊人的吸金能力,以2.34亿美元的月收入在全球手游排行榜上位列第二。4月5日,这款由腾讯游戏开发的多人在线战斗竞技游戏…

软考考前前怎么复习?

有一些经验,可以和大家分享一下。 软考的考试内容 软考包含许多科目,共分为五大类,27个专业。 软考的等级不同,考试内容也有所不同。初级和中级考试只包括两门科目,而高级则需要考三门科目。每门科目满分75分&#x…

knife4j-swagger

文章目录 knife4j-swagger第 1 步:引入 jar 包第 2 步:添加注释来开启 knife4j第 3 步:验证问题解决新增功能:ApiOperationSupport 注解新增功能:DynamicParameters 注解忽略参数属性 knife4j-swagger knife4j 是 Swa…

W801 实现获取天气情况

看了小安派(AiPi-Eyes 天气站)的源码,感觉用W801也可以实现。 一、部分源码 main.c #include "wm_include.h" #include "Lcd_Driver.h"void UserMain(void) {printf("\n user task \n");Lcd_Init();Lcd_Clea…

Qt官方示例---opengl

文件相对路径:Examples\Qt-5.9.1\opengl 2dpainting cube computegles31 contextinfo hellogl2 hellowindow paintedwindow qopenglwidget qopenglwindow textures threadedqopenglwidget

VirtualBox设置共享文件夹,用于在Window11 和 Ubuntu22 中共享文件,2024亲测可用

VirtualBox设置共享文件夹,用于在Window11 和 Ubuntu22 中共享文件,2024亲测可用 Windows操作 1、新建文件夹,用于共享 Linux操作 1、添加共享文件夹 共享文件夹路径:选择Windows系统中你需要共享的文件夹 共享文件夹名称&am…

ROS2入门21讲__第07讲__节点:机器人的工作细胞

目录 前言 通信模型 案例一:Hello World节点(面向过程) 运行效果 代码解析 创建节点流程 案例二:Hello World节点(面向对象) 运行效果 代码解析 创建节点流程 案例三:物体识别节点 …

小蓝和小青在做数字破解游戏

小蓝和小青在做数字破解游戏,设某图案由m*n的0和1点阵组成,依照以下规则破解连续一组数值,从点阵图第一行第一个符号开始计算,从左到右,由上至下。第一个数表示连续有几个0,第二个数表示接下来连续有几个1,…