Python框架之UnitTest

unittest 是python 的单元测试框架,unittest 单元测试提供了创建测试用例,测试套件以及批量执行的方案, unittest 在安装pyhton 以后就直接自带了,直接import unittest 就可以使用,测试人员用UnitTest来做自动化测试,即管理和执行用例。

一、UnitTest基本组成

测试人员使用此框架的原因:能够组织多个用例去执行、提供丰富的断言方法、能够生成测试报告。

1、测试发现:从多个py文件中收集并加载测试用例;

2、测试执行:将测试用例按照一定的顺序和条件去执行并生成结果;

3、测试判断:通过断言去判断结果是否正确;

4、测试报告:统计测试进度,通过率,生成报告;

UnitTest的组成部分

1、TestCase:用来写测试用例

2、TestSuite:测试套件,用来组装测试用例,即打包TestCase

3、TestRunner:测试执行,用来执行TestSuite

4、TestLoader:测试加载,对TestSuite功能的补充,用来组装TestCase

5、Fixture:测试夹具,是一种代码结构,前置方法和后置方法

TestCase测试用例

步骤:

(1)导包 unittest

(2)定义测试类,只需要继承unittest.TestCase类就是测试类

(3)书写测试方法,方法名必须以test开头

(4)执行代码

# (1)导包 unittest
import unittest
# (2)定义测试类,只需要继承unittest.TestCase类就是测试类
class TestDemo(unittest.TestCase):
    # (3)书写测试方法,方法名必须以test开头
    def test_method1(self):
        print('测试方法一')

    def test_method2(self):
        print('测试方法二')
# (4)执行代码
#  4.1在类名或者方法名后面右键运行。类名后面运行:执行类中所有的测试方法;在方法名后面,只执行当前的测试方法
#  4.2 在主程序中使用unittest.main()来执行
if __name__ == '__main__':
    unittest.main()

TestSuite和TestRunner

TestSuite(测试套件),用来组装测试用例,将多个测试用例脚本集合在一起。

使用步骤:

  1. 实例化测试套件:suite = unittest.TestSuite()

  2. 添加用例:suite.addTest(ClassName("MethodName"))

    ClassName:为类名;MethodName:为方法名

  3. 添加扩展:suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(ClassName))

  4. 添加扩展:suite.addTest(unittest.makeSuite(测试类名))

    把指定ClassName类中的测试用例全部添加到测试套件中

    案例: 两个用例文件testcase1.py和testcase2.py

    testcase1.py文件中的代码为;

import unittest


class TestDemo1(unittest.TestCase):

    def test_method1(self):
        print('测试方法1-1')

    def test_method2(self):
        print('测试方法1-2')

testcase2.py文件中的代码为;

# 1、导包
import unittest


# 2、定义测试类,继承unittest.TestCase就是测试类
class TestDemo2(unittest.TestCase):
    # 3、写测试方法,方法中的代码是真正的测试用例代码,方法名必须以test开头
    def test_method1(self):
        print('测试方法2-1')

    def test_method2(self):
        print('测试方法2-2')

测试套件和执行testsuite_testrunner.py文件中代码为(第一种添加测试套件的方法):

# 1、导包
import unittest
from testcase1 import TestDemo1
# 2、实例化套件对象unittest.TestSuite()
from testcase2 import TestDemo2

suite = unittest.TestSuite()
# 3、添加用例方法
# 3.1 套件对象.addTest(测试类名('测试方法名'))
suite.addTest(TestDemo1('test_method1'))
suite.addTest(TestDemo1('test_method2'))
suite.addTest(TestDemo2('test_method1'))
suite.addTest(TestDemo2('test_method2'))
# 4、实例化、执行对象unittest.TextTestRunner()
runner = unittest.TextTestRunner()
# 5、执行 执行对象
runner.run(suite)

执行结果:

image.png

附加:测试套件和执行testsuite_testrunner.py文件中代码为(第二种添加测试套件的方法):

# 1、导包
import unittest
from testcase1 import TestDemo1
# 2、实例化套件对象unittest.TestSuite()
from testcase2 import TestDemo2

suite = unittest.TestSuite()
# 3、添加用例方法
# 3.2 添加整个测试类,套件对象.addTest(unittest.makeSuite(测试类名))
suite.addTest(unittest.makeSuite(TestDemo1))
suite.addTest(unittest.makeSuite(TestDemo2))
# 4、实例化、执行对象unittest.TextTestRunner()
runner = unittest.TextTestRunner()去执行

()
# 5、执行 执行对象
runner.run(suite)

TestLoader 测试加载

用来加载TestCase到TestSuite中,即加载满足条件的测试用例,并把测试用例封装成测试套件

suite = unittest.TestLoader().discover(test_dir, pattern='test*.py')

自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件

test_dir: 为指定的测试用例的目录

pattern:为查找的.py文件的格式,默认为'test*.py'

import unittest

suite = unittest.TestLoader().discover('E:\pythonProject\pythonUnitTest', 'testcase*.py')
runner = unittest.TextTestRunner()
runner.run(suite)

Fixture:测试夹具

测试夹具是一种代码结构。Fixture控制级别:方法级别、类级别、模块级别(了解即可)。

方法级别(在每个测试用例执行前后都会自动调用,方法名是固定的)

使用方式:

初始化(前置处理):def setUp(self) --> 开始自动执行

销毁(后置处理):def tearDown(self) --> 最后自动执行

类级别(在类中,所有的测试方法执行前后,会自动执行一次,方法名是固定的):

使用方式:

初始化(前置处理):

@classmethod

def setUpClass(cls): 

销毁(后置处理):

@classmethod

def tearDownClass(cls): 

方法名固定的本质是:继承unittest的方法,并且进行覆盖是重写

模块级别 [了解]

运行于整个模块的始末,即:整个模块只会运行一次setUpModule和tearDownModule

使用方式:

初始化(前置处理):def setUpModule()

销毁(后置处理):def tearDownModule()

案例分析:

登录功能的测试用例:

(1)打开浏览器--1次

(2)打开网页,点击登录--每次

(3)输入用户名密码验证码1,点击登录--每次,测试方法1

(4)关闭网页--每次

..................................................................................

(2)打开网页,点击登录--每次

(3)输入用户名密码验证码2,点击登录--每次,测试方法2

(4)关闭网页--每次

..................................................................................

(2)打开网页,点击登录--每次

(3)输入用户名密码验证码3,点击登录--每次,测试方法3

(4)关闭网页--每次

以上案例分析有很多重复的代码,我们可以使用测试夹具优化代码

import unittest


class TestLogin(unittest.TestCase):
    def setUp(self) -> None:
        print('2、打开网页,点击登录--每次--前置')

    def tearDown(self) -> None:
        print('4、关闭网页--每次--后置')

    @classmethod
    def setUpClass(cls) -> None:
        print('1、打开浏览器--类前置')

    @classmethod
    def tearDownClass(cls) -> None:
        print('5、关闭浏览器--类后置')

    def test_1(self):
        print('3、输入用户名密码验证码1,点击登录--每次,测试方法1')

    def test_2(self):
        print('3、输入用户名密码验证码1,点击登录--每次,测试方法2')

    def test_3(self):
        print('3、输入用户名密码验证码1,点击登录--每次,测试方法3')

image.png

二、断言

断言:让程序代替人为判断测试程序执行结果是否符合预期结果的过程

常用的UnitTest断言方法

image.png

对于自动化测试人员来说,重点掌握:

(1)assertEqual(预期结果,实际结果)

判断预期结果和实际结果是否相等,如果相等,用例通过,如果不相等,抛出异常,用例不通过

(2)assertIn(预期结果,实际结果)

判断预期结果是否包含在实际结果中,如果存在,用例通过,如果不存在,抛出异常,用例不通过

import unittest


class TestAssert(unittest.TestCase):
    def test_equal_1(self):
        self.assertEqual(10, 10)    # 用例通过

    def test_assert_2(self):
        self.assertEqual(10, 20)    # 用例不通过

    def test_in01(self):
        self.assertIn('admin', '欢迎admin登录系统!')  # 包含...用例通过

    def test_in02(self):
        self.assertIn('addddmin', '欢迎登录系统!')  # 不包含...用例不通过

案例: 工具类中有一个求和的测试方法:

def add(a, b):
    sum = a+b
    return sum

使用断言测试该求和方法是正确:

import unittest
from tools import add


class TestAdd(unittest.TestCase):
    def test_1(self):
        self.assertEqual(3, add(1, 2))

    def test_1(self):
        self.assertEqual(5, add(3, 2))

    def test_1(self):
        self.assertEqual(7, add(4, 3))

    def test_1(self):
        self.assertEqual(13, add(8, 5))

三、参数化

通过参数的方式来传递数据,从而实现数据和脚本分离。并且可以实现用例的重复执行。

unittest测试框架,本身不支持参数化,但是可以通过安装unittest扩展插件parameterized来实现。

安装parameterized:pip install parameterized

image.png

参数化实现

导包:from parameterized import parameterized

使用@parameterized.expand装饰器可以为测试函数的参数进行参数化

我们继续对以上的求和方法使用参数化的方式进行测试,代码运行的时候,可以使用多种方式运行,比如:直接右键运行、main方法运行、suite运行等

import unittest
from tools import add
from parameterized import parameterized

data = [(1, 1, 2), (2, 3, 5), (3, 4, 7), (10, 11, 21)]


class TestAdd(unittest.TestCase):
    @parameterized.expand(data)
    def test_1(self, a, b, expect):
        self.assertEqual(expect, add(a, b))


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

扩展:

我们将参数化的测试数据保存在json文件中,如下;

[
  [1, 1, 2],
  [2, 3, 5],
  [3, 4, 7],
  [10, 11, 21]
]

image.png

读取json文件中的数据:

import json


def build_add_data():
    with open('add_data.json',encoding='utf-8')as f:
        data = json.load(f)

    return data

image.png

将读取的json文件中的数据当作参数传到测试用例中:

import unittest

from read_json import build_add_data
from tools import add
from parameterized import parameterized


class TestAdd(unittest.TestCase):
    @parameterized.expand(build_add_data)
    def test_1(self, a, b, expect):
        self.assertEqual(expect, add(a, b))


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

image.png

以上就是将数据保存在json文件中实现参数化,json文件中的数据复杂的时候,我们可以使用如下方式定义(并且推荐此方法):

image.png

此时读取json文件的方法需要修改为:

def build_add_data():
    with open('add_data.json', encoding='utf-8')as f:
        data_list = json.load(f)
        new_list = []
        for data in data_list:
            a = data.get('a')
            b = data.get('b')
            expect = data.get('expect')
            new_list.append((a, b, expect))
        return new_list

四、生成HTML测试报告

安装:pip install HTMLTestReport

测试报告生成步骤:

(1)导包

(2)封装测试套件

(3)实例化HTMLTestReport对象

report = HTMLTestReport(file_path, [title], [description])

参数说明:

file_path:测试报告文件路径

title:可选参数,为报告标题,如XXX测试报告

description:可选参数,为报告描述信息

(4)执行测试套件report.run(suite)

继续使用上述示例,针对求和的方法进行测试报告的生成

import unittest
from htmltestreport import HTMLTestReport
from testadd_paramterized import TestAdd

# 测试套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))

# 运行对象
runner = HTMLTestReport('test_add_report.html', '求和运算测试报告', '这是报告的描述!')
runner.run(suite)

运行之后将生成的html报告文件,使用浏览器打开,查看生成的报告,报告中执行失败的用例是故意写错,用来查看执行失败的情况:

image.png

image.png

image.png

使用绝对路径保存测试报告

在实际项目中往往会出现文件找不到的情况,此时需要使用绝对路径。

步骤:

(1)在项目的根目录中创建一个配置文件(app.py或者config.py)

(2)在这个文件中获取项目的目录,在其他代码中拼接起来,完成绝对路径

获取当前文件的绝对路径:abspath = os.path.abspath(__file__)

获取文件路径的目录名称:dirname = os.path.dirname(filepath)

案例:

app.py中的代码内容

import os

# 获取当前文件的绝对路径
path1 = os.path.abspath(__file__)
print(path1)

# 获取文件路径的目录名称
path2 = os.path.dirname(path1)
print(path2)

# 实际中直接合起来写就行
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

if __name__ == '__main__':
    print(BASE_DIR)

运行结果:

image.png

代码中的使用

# 测试套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))

# 运行对象
report_path = app.BASE_DIR + "test_add_report.html"  # 报告的路径
runner = HTMLTestReport(report_path, '求和运算测试报告', '这是报告的描述!')
runner.run(suite)

五、测试用例跳过

直接将测试函数标记成跳过@unittest.skip('代码未完成')

根据条件判断测试函数是否跳过@unittest.skipIf(condition, reason)

示例:

import unittest

ver = 10

class TestSkip(unittest.TestCase):
    @unittest.skip('此用例跳过,这是跳过的原因')
    def test_1(self):
        print('测试方法一')

    @unittest.skipIf(ver >= 10, '迭代版本大于等于10,此用例跳过')
    def test_2(self):
        print('测试方法二')

    def test_3(self):
        print('测试方法三')


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

image.png

行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。

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

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

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

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

相关文章

基于SpringBoot + Vue实现的校车调度管理系统设计与实现+毕业论文(12000字)+答辩PPT​(包运行成功)

介绍 本系统包含管理员、驾驶员两个个角色。 管理员角色:驾驶员信息管理、车辆信息管理、借调车辆管理、工作管理、车辆运营管理、报销申请审核。 驾驶员角色:个人信息查看、工作查看、借调车辆申请、车辆使用申请、报销申请提交。 运行环境 jdk1.8 id…

前端开发攻略---在输入框中输入中文但是还没选中的时候,搜索事件依然存在;中文输入法导致的高频事件。

1、演示 解决前 解决后 2、输入框事件介绍 compositionstart事件在用户开始使用输入法输入时触发。这意味着用户正在进行组合输入,比如在中文输入法中,用户可能正在输入一个多个字符的词语。在这个阶段,输入框的内容可能还没有完全确定&#…

消费增值新模式:让每一分钱都更有价值

亲爱的消费者们,大家好!今天我想和大家探讨一种新颖的消费方式——消费增值,它让您的每一次消费都蕴含了额外的价值,让消费变得更加有意义。 在过往的消费观念里,我们往往只是简单地将钱花出去,购买所需的商…

医院一站式后勤管理系统 processApkUpload.upload 任意文件上传漏洞复现

0x01 产品简介 医院一站式后勤管理系统由南京博纳睿通软件科技有限公司开发的一款基于现代医院后勤管理理念的业务系统,产品结合后勤业务管理特点,通过管理平台将后勤管理业务予以系统化、规范化和流程化,从而形成一套构建于平台之上且成熟完善的后勤管理体系,并可在此体系…

mysql的下载、安装

首先进入官网:MySQL 点击“downloads”进入下载界面 2.往下滑动滚轮,点击“mysql community...(公开版)” 3.往下滑,找到并单击“install for Windows” 4.选择版本:初学者可以使用较低版本,较…

SpringCloud框架 服务拆分和远程调用

数据库隔离避免耦合度过高,不同模块将自己的业务暴露为接口,供其他微服务调用 微服务远程调用技术Rest 在后端实现发送http请求 1.在启动类/配置类里注册RestTemplate启动对象 2.注入Bean对象使用

电商技术揭秘十四:大数据平台的选择与构建

相关系列文章 电商技术揭秘一:电商架构设计与核心技术 电商技术揭秘二:电商平台推荐系统的实现与优化 电商技术揭秘三:电商平台的支付与结算系统 电商技术揭秘四:电商平台的物流管理系统 电商技术揭秘五:电商平台…

一款牛逼的开源建站系统,轻松搭建专属博客网站(文末有福利)

今天给大家介绍一款牛逼的开源建站系统,支持多种方式部署,支持mardown、富文本、在线表格和思维导图等主流功能,轻轻松松帮你建立一个专属的、独一无二的博客网站。 博客功能 博文空间(便于博文组织,权限隔离) Markdown、Html富文本、电子表…

GD32F3系列单片机环境搭建

GD32单片机介绍 使用到开发板 GD32F303C-START 芯片型号:GD32F303CGT6 PinToPin单片机型号:STM32F103 GD32F303CGT6是超低开发预算需求并持续释放Cortex-M4高性能内核的卓越动力,为取代及提升传统的8位和16位产品解决方案,直接进…

Linux标准c库打开创建文件读写文件光标移动

fopen函数“const char *mode”参数选项。 结果:

【Css】table数据为空,以“-“形式展现

解决:class类名 它表示的是在一个名为class类名的元素内部,当该元素为空时,会在该元素的:before伪元素上应用一些样式。 这种写法通常用于在元素内容为空时,添加一些占位符或者提示文字

Hdevelop编辑器常用功能

1、灰度直方图 【阈值分割】——对应算子threshold 通过菜单【可视化】-【工具】-【灰度直方图】打开,打开后选中【变量窗口】的某张图片即可进行灰度直方图分析。 刚打开并选中某张图片: 调节【最小化】和【最大化】的两个竖线,此时图中绿…

【EM算法】算法及注解

EM算法又称期望极大算法,是一种迭代算法,每次迭代由两步组成:E步,求期望(expectation);M步,求极大(maximization)。 算法背景 如果概率模型的变量都是观测变…

第12届蓝桥杯java A组做题记录

A题:相乘 package JAVA12l蓝桥杯; //求2021的逆元public class 相乘 {static int mod (int)1e9 7;public static long qmi(long a,int k,int p){long res 1;while(k > 0){if(k % 2 1) res res * a % p;a a * a % p;k >> 1;}return res;}public stati…

【黑马头条】-day09用户行为-点赞收藏关注阅读不喜欢-数据回显-精度丢失解决

文章目录 1 long类型精度丢失问题1.1 解决1.2 导入jackson序列化工具1.3 自定义注解1.4 原理1.5 测试 2 用户行为要求3 创建微服务behavior3.1 微服务创建3.2 添加启动类3.3 创建bootstrap.yml3.4 在nacos中配置redis3.5 引入redis依赖3.6 更新minio 4 点赞4.1 实体类LikesBeha…

机器人方向控制中应用的磁阻角度传感芯片

磁阻传感器提供的输出信号几乎不受磁场变动、磁温度系数、磁传感器距离与位置变动影响,可以达到高准确度与高效能,因此相当适合各种要求严格的车用电子与工业控制的应用。所以它远比采用其它传感方法的器件更具有优势。 机器人的应用日渐广泛&#xff0…

ChatGPT们写高考作文会发生什么?

2023年的高考结束了,今年共有1291万考生参加了高考了,再次创造了历史参考人数之最。在高考中,要说什么最引人讨论,那高考作文当仁不让啊。今年随着ChatGPT的爆火,可谓是给文字工作者带来一大助力,如果让AI来…

2024腾讯一道笔试题--大小写字母移动

题目🍗 有一个字符数组,其中只有大写字母和小写字母,将小写字母移到前面, 大写字符移到后面,保持小写字母本身的顺序不变,大写字母本身的顺序不变, 注意,不要分配新的数组.(如:wCelOlME,变为wellCOME). 思路分析🍗 类似于冒泡排序,两两比较…

将本地项目上传到Github

首先安装git、创建github账号 1、创建一个新的仓库 2、创建SSH KEY。先看一下你C盘用户目录下有没有.ssh目录,有的话看下里面有没有id_rsa和id_rsa.pub这两个文件,有就跳到下一步,没有就通过下面命令创建。 ssh-keygen -t rsa -C "you…