unittest框架从编写测试脚本到生成测试报告

目录

1、什么是UnitTest框架

2、为什么使用UnitTest框架

3、UnitTest核心要素

4、UnitTest使用流程

5、unittest断言

6、TestCase测试用例

7、TestSuit测试套件

8、TestLoader测试加载

8.1、discover加载

8.2、defaultTestLoader通过类名、模块名加载

8.3、小结

9、Fixture测试夹具

10、参数化

10.1、环境准备

10 .2、通过元组列表实现参数化

10.3、使用json数据参数化

11、跳过

12、测试报告


1、什么是UnitTest框架

​ 概念:UnitTest是Python自带的一个单元测试框架,可以用它来做单元测试

2、为什么使用UnitTest框架

  • 能够组织多个用例去执行

  • 提供丰富的断言方法

  • 能够生成测试报告

3、UnitTest核心要素

  • TestCase(测试用例)

  • TestSuite(测试套件,把多个TestCase集成到一个测试TestSuite)

  • TextTestRunner(执行测试用例)

  • Fixture(测试夹具)

4、UnitTest使用流程

第一步:导入unittest模块

第二步:创建一个类,这个类必须继承自UnitTest.TestCase类

第三步:类中每个方法代表一个测试用例,方法名必须以test开头

第四步:将测试用例加入到TestSuite

第五步:使用TextTestRunner执行

5、unittest断言

    让程序代替人判断程序执行结果是否符合预期结果的过程,需要在测试用例中对测试结果进行断言。

assertEqual(a, b, msg=None)      # a == b    断言a和b是否相等,相等则测试用例通过
assertNotEqual(a, b,msg=None)# a != b 断言a和b是否相等,不相等则测试用例通过
assertTrue(x,msg=None)# x is True 断言x是否True,是True则测试用例通过  
assertFalse(x,msg=None) # x is False 断言x是否False,是False则测试用例通过
assertIn(a, b,msg=None)# a in b 断言a是否在b中,在b中则测试用例通过  
assertNotIn(a, b,msg=None)   # a not in b 断言a是否在b中,不在b中则测试用例通过
  • assertEqual(参数1,参数2,msg=None)

    • 如果参数1和参数2相等,断言成功,否则断言失败

    • 参数1存放实际结果,参数2存放预期结果

    • msg默认信息为None,可以给msg指定信息,当断言失败时,会作为错误信息返回

6、TestCase测试用例

        在编写测试用例之前,我们需要创建一个存放测试用例的类,导入unittest,并且要继承unittest.TestCase类,该类中的方法必须要以test开头

        下面创建两个测试类,StringTest和NumberTest,分别写了两个测试方法

StringTest类

import unittest
class StringTest(unittest.TestCase):
    def test_Method1(self):
        self.assertIn("hello","hello world")
    def test_Method2(self):
        self.assertEqual("H","Happy")

NumberTest类

import unittest
class NumberTest(unittest.TestCase):
    def test_funa(self):
        self.assertEqual(1,2,"两个参数不相等")
    def test_funb(self):
        self.assertEqual(2,2)

        这两个类可以直接运行,直接在该类中,右键点击Run Unittests for 模块名.类名,就可以直接查看测试结果,或者也可以加入如下代码,直接调用unittest.main()来执行

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

       单独执行NumberTest类,一共两条测试用例,一条通过,一条不通过,并打印了错误信息

7、TestSuit测试套件

       上面介绍了如何执行单个测试类里面的测试用例,但是测试是不可能只写一个测试类,当需要执行多个测试类中的测试方法时,需要用到测试套件,把测试用例组装起来。

        1、实例化:suite = unittest.TestSuit() (suite:为TestSuit实例化的名称)

        2、添加单个用例:

suit.addTest(ClassName("MethodName")) (ClassName:为类名 MethodName:为方法名)

        3、添加多个测试用例,参数为列表suit.addTests([ClassName("MethodName1"),ClassName("MethodName2")]) 

​        4、TestSuit需要配合TextTestRunner才能被执行,

还以StringTest和NumberTest为例,介绍TestSuit的使用

#导入测试类
from frame_unittest.numberTest import NumberTest
from frame_unittest.stringTest import StringTest
import unittest
if __name__ == "__main__":
    suit = unittest.TestSuite() #实例化测试套件
    suit.addTest(NumberTest("test_funa"))  #单个添加测试用例
    suit.addTest(NumberTest("test_funb"))
    suit.addTests([StringTest("test_Method1"),StringTest("test_Method2")])  #添加多个测试用例
    runner = unittest.TextTestRunner() #实例化TextTestRunner
    runner.run(suit)  #执行测试用例

8、TestLoader测试加载

        作用和TestSuit作用一样,组装用例代码,同样也需要使用TextTestRunner去执行,  用来加载TestCase到TestSuit中,即加载满足条件的测试用例,测试用例封装成测试套件

8.1、discover加载

        使用unnitest.TestLoader,通过该类下面的discover()方法自动搜索指定开头的.py文件,并查找到的测试用例组装到测试套件

        用法:suit = unittest.TestLoader().discover(test_dir,pattern='test*.py')

import unittest
import os
if __name__ == "__main__":

    path = os.path.dirname(__file__) #获取当前文件所在目录的路径
    suit = unittest.TestLoader().discover(path,"*Test.py") #加载当前目录下,以Test.py结尾的模块
    runner = unittest.TextTestRunner() #实例化TextTestRunner
    runner.run(suit)  #执行测试用例

8.2、defaultTestLoader通过类名、模块名加载

           defaultTestLoader可以通过类名和模块名的方式加载,与TestLoader中discover不同的点在于,defaultTestLoader还需要把加载的内容添加到TestSuit中,discover则不用。执行都需要使用TextTestRunner去执行

        下面的测试用例还是借用上述的StringTest和NumberTest,使用类名和模块名两种当时执行测试用例

      unittest.defaultTestLoader.loadTestsFromTestCase(类名)  添加一个类
import unittest
from frame_unittest.numberTest import NumberTest
from frame_unittest.stringTest import StringTest
#加载的是类名
nt =unittest.defaultTestLoader.loadTestsFromTestCase(StringTest)
st =unittest.defaultTestLoader.loadTestsFromTestCase(NumberTest)
suit = unittest.TestSuite([st,nt])
unittest.TextTestRunner().run(suit)

unittest.defaultTestLoader.loadTestsFromModule(模块名)  添加一个模块
import unittest
#导入需要加载的模块
from frame_unittest import numberTest
from frame_unittest import stringTest
names =[numberTest,stringTest]
modules=[]
#加载模块名
for name in names:
    module=unittest.defaultTestLoader.loadTestsFromModule(name)
    modules.append(module)
suit = unittest.TestSuite(modules)
unittest.TextTestRunner().run(suit)

8.3、小结

        组装测试套件有多种方式

        方式一:添加单个测试类的单个测试方法 组装到测试套件中  addTest()

        方式二:搜索该路径下所有符合命名规则的模块组装到测试套件中 discover()

        方式三:通过加载类名的方式组装到测试套件   loadTestsFromTestCase()

        方式四:用过加载模块名的方式组装到测试套件  loadTestsFromModule()

  • 所有的TestCase最终都是用TextTestRunner来执行的

  • TextTestRunner执行的是TestSuit

  • 一个TestSuit中有多个TestCase

9、Fixture测试夹具

        Fixture是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture

可以在测试用例执行之前调用指定的函数,在测试用例执行之后调动指定的函数

Fixture控制级别

  • 方法级别

    • 每个方法执行前和执行后都自动调用函数

  • 类级别

    • 不管类中有多少方法,一个类执行前后都自动调用函数

  • 模块级别

    • 不管一个模块(一个模块就是一个py文件)中有多少类,模块执行前后自动调用函数

1、方法级

在TestCase,也就是测试用例所在的class中定义方法

def setUp(self)当测试用例执行前,自动被调用

def tearDown(self)当测试用例执行后,自动被调用

如果一个TestCase中有多个测试用例,那么setUp和tearDown就会被自动调用多次

import unittest
def add(a,b):
    sum = a + b
    return sum
​
class my_test(unittest.TestCase):
    def setUp(self):
        print("setup被调用了")
    def tearDown(self):
        print("teardown被调用了")
    def test_001(self):
        print(add(4,5))
​
    def test_002(self):
        print(add(0,6))
​
    def test_003(self):
        print(add(2,4))

2、类级别:

  • 不管类中有多少个方法,一个类开始的时候自动调用函数,结束之后自动调用函数

  • 类级别的fixture一定要有类方法@classmethod

import unittest
def add(a,b):
    return a+b
​
​
class my_test_demo(unittest.TestCase):
​
    @classmethod
    def setUpClass(cls):
        print("这个是类级别测试开始")
    @classmethod
    def tearDownClass(cls):
        print("这个是类级别的结束")
​
    def test_01(self):
        print(add(3,2))
    def test_02(self):
        print(add(1,2))

3、模块级别:

  • 不管py文件有多少个类,以及类中有多少个方法,只自动执行一次

  • def setUpModule() 在py文件开始的时候自动调用

  • def tearDownModule()在文件结束的时候自动调用

import unittest
def add(a,b):
    return a+b
​#模块级别
def setUpModule():
    print("setUpModule自动调用了")
​​#模块级别
def tearDownModule():
    print("tearDownModule调用结束了")
​
​
class my_test_demo(unittest.TestCase):
​    #类级别
    @classmethod
    def setUpClass(cls):
        print("这个是类级别测试开始")
    @classmethod
    def tearDownClass(cls):
        print("这个是类级别的结束")
​
    def test_01(self):
        print(add(3,2))
    def test_02(self):
        print(add(1,2))
​    #方法级别
    def setUp(self):
        print("setup被调用了")
    def tearDown(self):
        print("teardown被调用了")

10、参数化

        测试用例中使用参数化的场景:​多个测试用例代码相同,只是测试数据不同,预期结果不同,可以把多个测试用例通过参数化技术合并为一个

       通过参数的方式来传递数据,从而实现数据和脚本分离。并且可以实现用例的重复执行。(在书写用例方法的时候,测 试数据使用变量代替,在执行的时候进行据说传递)
    unittest 测试框架,本身不支持参数化,但是可以通过安装unittest扩展插 件 parameterized 来实现。

10.1、环境准备

因为参数化的插件 不是 unittest 自带的,所以想要使用 需要进行安装

Python 中 包(插件,模块) 的安装,使用 pip 工具, 在终端(cmd)中执行
pip install parameterized
pip install -i https://pypi.douban.com/simple/ parameterized
pip list     # 查看安装的所有的插件

10 .2、通过元组列表实现参数化

​      定义一个加法函数,模块名为tools

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

    定义一个测试类,模块名为TestAdd.py

from parameterized import parameterized  #导入parameterized
import unittest

from frame_unittest.tools import add
#使用data存放一组测试数据
data = [(1, 1, 2), (1, 2, 3), (2, 3, 5), (4, 5, 9)]


class Test_Add(unittest.TestCase):
    @parameterized.expand(data) #data数据与测试用例的参数一一对应
    def test(self,a,b,expect):
        self.assertEqual(add(a,b),expect)
if __name__ == "__main__":
    unittest.main()

10.3、使用json数据参数化

JSON格式一

定义一个data.json

[
  [1, 1, 2],
  [1, 2, 3],
  [2, 3, 5],
  [4, 5, 9],
  [10, 20, 30]
]

定义一个TestAdd_Method.py

import unittest
import os
import json
from parameterized import parameterized
from frame_unittest.tools import add
#获取当前文件所在目录
path = os.path.abspath(os.path.dirname(os.getcwd()))
#定义一个读取json数据的方法
def read_data():
    with open(path+"/data/add.json",mode="r",encoding="utf-8") as file:
        data = json.load(file)
        return data
class TestMethod(unittest.TestCase):
    @parameterized.expand(read_data())
    def test_method(self,a,b,expect):
        self.assertEqual(add(a,b),expect)

JSON格式二

定义一个data1.json

[
  { "a": 1, "b": 2, "expect": 3 },
  { "a": 11, "b": 22, "expect": 33 },
  { "a": 12, "b": 23, "expect": 35 },
  { "a": 14, "b": 25, "expect": 39 }
]

建立一个模块名为addmethod.py的测试类

import os
import unittest
import json
from frame_unittest.tools import add
from parameterized import parameterized
​
def readdata():
    path = os.path.abspath(os.path.dirname(os.getcwd()))
    with open(path+"/data/add1.json",mode="r",encoding="utf-8") as file:
        datas = json.load(file)  #读取json文件
        list_data = []
        for data in datas:
            a = data.get("a")
            b = data.get("b")
            expect = data.get("expect")
            list_data.append((a,b,expect))
    return list_data #返回[(),(),()...]的数据格式
             #list_data.append(tuple(data.values()))
​
class AddMethod(unittest.TestCase):
    @parameterized.expand(readdata())
    def test_add(self,a,b,expect):
        self.assertEqual(add(a,b),expect)

11、跳过

        跳过:对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行(简单来说, 不想执行的测试方法,可以 设置为跳过)
        - 直接将测试函数标记成跳过
                @unittest.skip('跳过的原因')
        - 根据条件判断测试函数是否跳过
                @unittest.skipIf(判断条件, reason='原因') # 判断条件为 True, 执行跳过
import unittest
version = 35
class TestSkip(unittest.TestCase):
    @unittest.skip('跳过此条不执行')
    def test_1(self):
        print('方法一')
    @unittest.skipIf(version >= 30, '版本号大于等于 30, 测方法不用执行')
    def test_2(self):
        print('方法二')
    def test_3(self):
        print('方法三')
if __name__ == '__main__':
    unittest.main()

执行结果

============================= test session starts =============================
collecting ... collected 3 items

mm.py::TestSkip::test_1 SKIPPED (跳过此条不执行)                         [ 33%]
Skipped: 跳过此条不执行

mm.py::TestSkip::test_2 SKIPPED (版本号大于等于 30, 测方法不用执行)      [ 66%]
Skipped: 版本号大于等于 30, 测方法不用执行

mm.py::TestSkip::test_3 PASSED                                           [100%]方法三


======================== 1 passed, 2 skipped in 0.02s =========================

12、测试报告

使用第三方的报告模版,生成报告 HTMLTestReport, 本质是 TestRunner

- 安装

pip install -i https://pypi.douban.com/simple/ HTMLTestReport

- 使用

  1. 导包 unittest、HTMLTestReport

  2. 组装用例(套件, loader )

  3. 使用 HTMLTestReport 中的 runner 执行套件

  4. 查看报告

以最开始的stringtest和numbertest为例

import unittest
from htmltestreport import HTMLTestReport
import os
if __name__ == "__main__":
    path = os.path.dirname(__file__)
    suit = unittest.TestLoader().discover(path+"/","*test.py")
    # runner = HTMLTestReport(报告的文件路径后缀.html, 报告的标题, 其他的描述信息)
    runner = HTMLTestReport("report.html","数据类型测试报告")
    runner.run(suit)

生成的测试报告如下

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值