【Python】单元测试框架unitest及其高级应用

news2024/11/15 8:22:16

目录

Unittest

简单使用示例

重要概念

断言方法

深入

高级应用

认识Page Object

 资料获取方法


Unittest

Unittest是python的一个单元测试框架,但是它不仅适用于单元测试,还适用自动化测试用例的开发与执行。我们可以很方便的使用它组织执行测试用例,使用它提供的丰富的断言方法进行测试结果比对,并最终结合HTMLTestRunner生成测试报告完成整个自动化测试流程。

简单使用示例

创建被测类calculator.py

class count:
    def _init_(self,a,b)
        self.a = int(a)
        self.b = int(b)
     #计算加法
    def add(self):
       return self.a + self.b

通过unittest单元测试框架编写单元测试用例 test.py

from calculator import count
import unitest
class TestCount(unitest.TestCase):
    def setUp(self):
        print("test start")
    def test_add(self):
        j = count(2,3)
        self.assertEqual(j.add(),5)
    def tearDown(self):
        print("test end") 
if _name_ == '_main_':
    unittest.main()

说明:

  1. 首先引入unitest模块,创建testcount类继承unitest的testcase类。
  2. setUp():用于测试用例执行前的初始化工作,与tearDown()相呼应,用于执行后的善后工作。
  3. test_add中调用count类并传入要计算的数,通过调用add()方法得到两数相加的返回值,这里不再使用繁琐的异常处理,而是调用unitest框架所提供的assertEqual()对add()的返回值进行断言判断两者是否相等。assertEqual()方法是由testcase类继承而来的。
  4. main():unitest提供了全局的main()方法,使用它可以方便的将一个单元测试模块变成可以直接运行的测试脚本。main()方法使用Testloader类来搜索所有包含在该模块中以“test”命名开头的测试方法。
  5. name:作为模块的内置属性,简单地说就是.py文件的调用方式。.py文件有两种使用方式作为模块调用和直接使用,如果它等于“main”就表示是直接使用

重要概念

  1. TestCase:一个TestCase的实例就是一个测试用例,是一个完整的测试流程,包括测试前准备环境的搭建(setUp),实现测试过程的代码(run),测试后环境的还原(tearDown).
  2. Test Suite:把多个测试用例集合在一起来执行。可以通过addTest加载TestCase到Test Suite中,从而返回一个TestSuite实例。
  3. Test Runner:测试的执行,通过TextTestRunner类提供的run()方法来执行Test Suite/TestCase。Test Runner可以使用图形界面,文本界面,或者返回一个特殊的值的方式来表示测试执行的结果。
  4. Test Fixture:对一个测试用例环境的搭建和销毁。通过覆盖TestCase的setUp()和tearDown()方法来实现。tearDown()为下一个测试用例提供一个干净的环境。
from calculator import count
import unitest
class TestCount(unitest.TestCase):
    def setUp(self):
        print("test start")
    def test_add(self):
        j = count(2,3)
        self.assertEqual(j.add(),5)
   def test_add2(self):
        j = count(7,8)
        self.assertEqual(j.add(),15)
    def tearDown(self):
        print("test end") 
if _name_ == '_main_':
    unittest.main()
#构建测试集
suite = unittest.TestSuite()
suite.addTest(TestCount("test_add2"))
#执行测试
runner = unittest.TextTestRunner()
runner.run(suite)

本例只执行第二个测试用例,

  1. 调用unittest框架的TestSuite()来创建测试套件。
  2. 通过它所提供的addTest()方法来添加测试用例test_add2。
  3. 调用unitest框架的TextTestRunner().
  4. 通过它下面的run()方法来运行suite所组装的测试用例。

断言方法

unittest框架的TestCase类提供的断言方法用于测试结果的判断

判断第一个参数和第二个参数是否相等

-assertEqual(first,second,msg=None)
# 如果不相等则测试失败,msg为可选参数,用于定义测试失败时打印的信息。
self.assertEqual(j.add(),15,msg="测试结果不等于15")

格式:-assertNotEqual(first,second,msg=None)则与之相反

判断表达式是true(或false)

-assertTrue(expr,msg=None)
-assertFalse(expr,msg=None)

创建count.py用于判断质数的

def is_prime(n):
    if n<=1:
        return False
   for i in range(2,n):
        if n % i = = 0:
            return False
  retun True

测试用例:调用is_prime()函数和unittest

self.assertTrue(is_prime(7),msg="is not prime")

判断第一个参数是否在第二个参数中,就是第二个参数是否包含第一个参数。

-assertIn(first,second,msg=None)  
-assertNotIn(first,second,msg=None)

测试用例(部分):

def test_case(self):
    a = "hello"
    b = "hello world"
    self.assertIn(a,b,msg="a is not in b")

判断第一个参数和第二个参数是否为同一对象

-assertIs(first,second,msg=None)
-assertIsNot(first,second,msg=None)

判断表达式是否为None对象

-assertIsNone(expr,msg=None)
-assertIsNotNone(expr,msg=None)

判断obj是否为cls的一个实例格式:

-assertIsInstance(obj,cls,msg=None)
-assertNotIsInstance(obj,cls,msg=None)

深入

组织单元测试用例

  • 方法1.setUp()和setDown方法分别作用于每个测试用例的开始和结束
  • 方法2.如果每个类中的setUp()和setDown方法所做的事情是一样的,那么可以封装成一个自己的测试类

discover更多测试用例

如果单元测试用例达到成百上千个,可以将这些用例按照所测试的功能进行拆分,分散到不同的测试文件中
最后再创建用于执行所有测试用例的runtest.py文件。

  • 方法1:可以通过addTest()加载TestCase到TestSuite中。用于少量的测试用例
  • 方法2:使用TestLoader类提供的discover()方法来加载所有的测试用例。正常情况下,不需要创建这个类的实例,unittest提供了可以共享的defaultTestLoader类,可以使其子类和方法创建实例,discover()方法就是其中之一。
  • discover(start_dir,pattern='test*.py',top_level_dir=None)
  • start_dir:要测试的模块名或测试用例的目录
  • pattern='test.py':表示用例文件名的匹配原则,此处文件名以“test”开头的“.py”类型的文件,“”表示任意多个字符。
  • top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,默认为None.

用例执行的原则

unittest框架默认根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。所以TestAdd会优于TestBdd类被执行,test_aaa()方法会优于test_ccc被执行,因而它并没有按照用例从上到下的顺序执行。

对于测试目录和测试文件来说,unittest框架同样是按照这个规则来加载测试用例的。
如果按照指定的顺序执行,可以通过TestSuite类的addTest()方法按照一定的顺序加载。不能默认main()方法了。需要构造测试集,然后通过run()方法执行测试。

注意:discover()的加载测试用例的规则与main()方法相同,所以只能通过测试用例的命名来提高被执行的优先级。

执行多级的用例

discover()方法中的start_dir只能加载当前目录下的.py文件,如果加载子目录下的.py文件,需在每个子目录下放一个_init_.py文件。

跳过测试和预期失败

unittest提供了实现某些需求的装饰器,在执行测试用例时每个装饰前面加@符号。

  • unittest.skip(reason):无条件的跳过装饰的测试,说明跳过测试的原因
  • unittest.skipIf(condition,reason):跳过装饰的测试,如果条件为真。
  • unittest.skipUnless(condition,reason):跳过装饰的测试,除非条件为真。
  • unittest.expectedFailure():测试标记为失败,不管执行结果是否失败,统一标记为失败,但不会抛出错误信息。

fixtures

fixtures可以形象的把他看作是夹心饼干外层的两片饼干,这两片饼干就是setUp/tearDown,中间的心就是测试用例,除此以外,unittest还提供了更大范围的fixtures,例如对于测试类和模块的fixtures。

  • setUpModule/tearDownModule:在整个模块的开始和结束时被执行。
  • setUpClass/tearDownClass: 在测试类的开始和结束时被执行。
  • setUp/tearDown:在测试用例的开始与结束时被执行
    注意:setUpClass/tearDownClass的写法稍有不同,首先通过@classmethod进行装饰,其次方法的参数为cls,也可以是别的。每一个上面都要进行装饰

高级应用

HTMLTestRunner

HTMLTestRunner是python标准库unittest单元测试框架的一个拓展,它生成易于使用的HTML测试报告。
HTMLTestRunner下载地址:HTMLTestRunner - tungwaiyip's software
这个拓展只有一个HTMLTestRunner.py文件,选中后单击鼠标右键,在弹出的快捷菜单中选择目标另存为,将它保存到本地。安装方法是将其复制到python安装目录下即可。

  • windows:将下载的文件保存到...\python35\Lib目录下
  • Ubuntu:以root身份将HTMLTestRunner.py文件复制到/usr/local/python3.4/dist-packages/目录下。

HTMLTestRunner.py文件是基于python2开发的,若要支持python3环境需要对其中的部分内容进行修改。

生成HTML测试报告

  1. 将HTMLTestRunner模块用import导入进来
  2. 通过open()方法以二进制写模式打开当前目录下的result.html,如果没有,则自动创建该文件。
  3. 调用HTMLTestRunner模块下的HTMLTestRunner类,stream指定测试报告文件,title用于定义测试报告的标题,
    description用于定义测试报告的副标题。
  4. 最后,通过HTMLTestRunner的run()方法来运行测试套件中所组装的测试用例。
  5. 通过close()关闭测试报告文件。

更易读的测试报告

方法:加注释并用一种方法读取
在类和方法的下方,通过三引号(""" """或''' ''')来添加docstring类型的注释,这类注释在平时调用的时候
不显示,可以通过help()方法来查看类或方法的这种注释。

HTMLTestRunner可以读取docstring类型的注释,所以只需给测试类或方法添加这种类型的注释即可。

测试报告名称建议

在每次运行测试之前,都要手动修改报告的名称,如果忘记修改,就会把之前的报告覆盖,为了使每次生成的报告名称都不重复并且有意义,最好的方法是在报告名称中加入当前时间,这样生成的报告既不会重叠,又能更清晰的知道报告的生成时间。

  • time.time():获取当前时间戳 比如:1445694559.2290168
  • time.ctime():当前时间的字符串形式 比如:'sat oct 24 21:49:29 2015'
  • time.localtime():当前时间的struct_time形式 比如:tm_year=2015,tm_mon=10,tm_mday=24,..........等等。
  • time.strftime("%Y_%m_%d %H:%M:%s"):用来获得当前时间,可以将时间格式化为字符串。比如:'2015_10_24 21:50:15'

方法:通过时间操作的方法以指定的格式获取当前时间,将当前时间的字符串赋值给now变量,将now通过加号(+)拼接到生成的测试报告的文件名中,再次运行测试用例,生成测试报告文件名。

项目集成测试报告

目前HTMLTestRunner只是针对单个测试文件生成测试报告,若要使其作用于整个测试项目,
要将它集成到runtest.py文件中,对其文件进行修改。

认识Page Object

Page Object设计模式的优点

  1. 减少代码的重复性
  2. 提高测试用例的可读性
  3. 提高测试用例的可维护性,特别是针对UI频繁变化的项目

为web页面编写测试时,需要操作该web页面上的元素,如果在测试代码中直接操作HTML元素,那么你的代码是极其脆弱的,因为UI经常变动。我们可以将一个page对象封装成一个HTML页面,然后通过提供的应用程序特定的API来操作页面元素,而不是在HTML中四处搜寻。
page对象应当将在GUI控件上所有查询和操作数据的行为封装为方法,即使改变具体的控件,page对象的接口也不应当发生变化。

“页面”对象不仅是针对每个页面建立一个这样的对象,对由重要意义的元素也可以独立为一个page对象。

Page Object实例

  1. 创建page类
  2. 创建LoginPage类
  3. 创建test_user_login()函数
  4. 创建main()函数

 资料获取方法

【留言777】

各位想获取源码等教程资料的朋友请点赞 + 评论 + 收藏,三连!

三连之后我会在评论区挨个私信发给你们~

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

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

相关文章

JVM垃圾回收篇-垃圾回收算法

JVM垃圾回收篇-垃圾回收算法 标记清除&#xff08;Mark Sweep&#xff09; 概念 collector指的就是垃圾收集器。 mutator是指除了垃圾收集器之外的部分&#xff0c;比如说我们的应用程序本身。 mutator的职责一般是NEW(分配内存)、READ(从内存中读取内容)、WRITE(将内容写入内…

CSMA/CD协议原理

共享总线以太网具有天然的广播特性&#xff0c;即使总线上某个站点给另一个站点发送单播帧&#xff0c;表示帧的信号也会沿着总线传播到总线上的其他各站点 。 当某个站点在总线上发送顿时&#xff0c;此时&#xff0c;如果总线上的其他站点也要在总线当某个站点在总线上发送顿…

Qt应用开发(基础篇)——时间微调输入框 QDateTimeEdit、QDateEdit、QTimeEdit

一、前言 QAbstractSpinBox是全部微调输入框的父类&#xff0c;这是一种允许用户通过点击上下箭头按钮或输入数字来调整数值的图形用户界面控件&#xff0c;父类提供了当前值text、对齐方式align、只读readOnly等通用属性和方法。在上一篇数值微调输入框中有详细介绍。 QDateTi…

资深java程序员的IDEA的常用设置

设置入口 打开项目以后也可以在左上角File-->setting进行设置&#xff0c;不过部分设置的是该项目的&#xff0c;换个项目可能就变了&#xff0c;建议打开项目之前就设置。 一般新的idea软件默认是下图页面&#xff0c;或者打开项目后可以点击File-->Close Project退到…

【CI/CD】Git Flow 分支模型

Git Flow 分支模型 1.前言 Git Flow 模型&#xff08;本文所阐述的分支模型&#xff09;构思于 2010 年&#xff0c;也就是 Git 诞生后不久&#xff0c;距今已有 10 多年。在这 10 多年中&#xff0c;Git Flow 在许多软件团队中大受欢迎。 在这 10 多年里&#xff0c;Git 本身…

C++异常使用

异常关键字&#xff1a; try&#xff1a;在try部可检测异常 catch&#xff1a;当发现异常捕获处 throw&#xff1a;抛出异常处 noexcept&#xff1a;被修饰函数内部不会发生异常 允许抛出和捕捉各种类型的数据。 int main() {try{func();}catch(const char*e){ //捕捉字符…

计算机是怎么存储和识别人类高级语言的

目录 1、计算机是怎么“存储”人类的高级语言的&#xff1f;2、 UTF-8和UTF-32的区别3、UTF-8是如何区分字节的长度呢&#xff1f;&#xff08;即如何识别这一串二进制是多少个字节的&#xff1f;&#xff09;4、计算机是如何识别人类的高级语言的&#xff1f; 1、计算机是怎么…

idea如何开启多个客户端(一个代码开启多个客户端运行)

1.在编程界面UdpEchoClient的下拉列表中找到Edit Configurations...并点击 2.点击Modify options 3.点击Allow multiple instances将其勾选上 4.点击ok 在经历了以上的设置以后&#xff0c;再次运行客户端的程序便会创建一个新的客户端运行&#xff08;有了一个新的运行窗口&am…

【AI】《动手学-深度学习-PyTorch版》笔记(十四):多层感知机

AI学习目录汇总 1、多层感知机网络结构 1.1 线性模型:softmax回归 在前面介绍过,使用softmax回归来处理分类问题时,每个输出通过都一个仿射函数计算,网络结构如下,输入和输出之间为全链接层: 1.2 多层感知机 多层感知机就是在输入和输出中间再添加一个或多个全链接…

解数独(Java)

题目链接&#xff1a; 力扣 题目详情&#xff1a; 37. 解数独t编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只…

研发工程师玩转Kubernetes——使用emptyDir在同一Pod不同容器间共享数据

kubernets可以通过emptyDir实现在同一Pod的不同容器间共享文件系统。 正如它的名字&#xff0c;当Pod被创建时&#xff0c;emptyDir卷会被创建&#xff0c;这个时候它是一个空的文件夹&#xff1b;当Pod被删除时&#xff0c;emptyDir卷也会被永久删除。 同一Pod上不同容器之间…

【数据分析】pandas (三)

基本功能 在这里&#xff0c;我们将讨论pandas数据结构中常见的许多基本功能 让我们创建一些示例对象&#xff1a; index pd.date_range(“1/1/2000”, periods8) s pd.Series(np.random.randn(5), index[“a”, “b”, “c”, “d”, “e”]). df pd.DataFrame(np.random.…

BDA初级分析——界定问题

数据分析&#xff0c;从界定问题开始 一、界定问题的作用 如何从现有台式机企业客户中挑选出那些想购买服务器的企业客户&#xff1f; 问题中的陷阱&#xff0c;隐藏的假设条件 假设1: 在购买服务器的客户中&#xff0c;只有0.01%的客户是购买过公司台式机的客户&#xff0…

超详细的Linux基础命令

文章目录 前言Linux目录结构Linux命令通用格式ls 命令什么是工作目录什么是 HOME 目录 目录切换相关命令cd 命令pwd 命令 特殊的路径符创建目录文件操作相关命令touch 命令cat 命令more 命令cp 命令mv 命令rm 命令通配符 查找命令which 命令find 命令按文件名查找文件按文件大小…

无人驾驶实战-第十一课(控制理论)

在七月算法上报了《无人驾驶实战》课程&#xff0c;老师讲的真好。好记性不如烂笔头&#xff0c;记录一下学习内容。 课程入口&#xff0c;感兴趣的也可以跟着学一下。 ————————————————————————————————————————— 无人驾驶中控制系…

1、如何实现两台电脑之间数据相互读写

一、确保两台电脑在同一个局域网中&#xff0c;可以使用网线【动态配置】进行两台电脑互连。 二、静态配置: 将IP地址和网关设为192.168.0.1&#xff0c;目的是让这台电脑做另一台电脑的网关&#xff0c;子网掩码一点击会自动添加。第二台电脑同样打开设置&#xff0c;此处IP地…

[oeasy]python0082_[趣味拓展]控制序列_清屏_控制输出位置_2J

光标位置 回忆上次内容 上次了解了键盘演化的过程 ESC 从 组合键到 独立按键 ESC的作用 是 进入 控制序列配置 控制信息控制信息 \033[y;xH 设置光标位置\033[2J 清屏 这到底怎么控制&#xff1f;&#xff1f;&#xff1f;&#x1f914;谁来实现这些功能&#xff1f; 控制…

【大数据】Flink 详解(二):核心篇 Ⅱ

Flink 详解&#xff08;二&#xff09;&#xff1a;核心篇 Ⅱ 22、刚才提到 State&#xff0c;那你简单说一下什么是 State。 在 Flink 中&#xff0c;状态 被称作 state&#xff0c;是用来保存中间的计算结果或者缓存数据。根据状态是否需要保存中间结果&#xff0c;分为 无状…

【Linux】网络基础1

文章目录 网络基础11. 计算机网络背景1.1 网络发展 2. 认识协议2.1 网络协议2.2 OSI七层模型2.3 TCP/IP五层&#xff08;或四层&#xff09;模型 3. 网络传输基本流程3. 1 数据报封装和分用 4. 网络中的地址管理4.1 认识IP地址 5. 认识MAC地址 网络基础1 1. 计算机网络背景 1…

(番外篇)Michael.W基于Foundry精读Openzeppelin第22期——内联汇编staticcall

&#xff08;番外篇&#xff09;Michael.W基于Foundry精读Openzeppelin第22期——内联汇编staticcall 0. 版本1. 关于内联汇编staticcall2. foundry代码验证2.1 目标合约2.2 返回数据字节长度为322.3 返回数据字节长度为642.4 返回数据为动态数组 0. 版本 [forge-std]&#xf…