UnitTest(自动化测试框架)-单元测试、Fixture、断言、HTMLTestRunner自动生成测试报告

什么是unitTest?

  • UnitTest是python自带的自动化测试框架
  • UnitTest主要包含的内容
    • TestCase:测试用例
    • TestSuite:测试套件,把多个TestCase集成到一个测试TestSuite
    • TestRunner:执行测试用例
    • TestLoader:自动从代码中加载多个测试用例TestCase
    • Fixture:Test特性

TestCase

  • 第一步:导入unittest模块
  • 第二步:实现一个类,必须继承unittest.TestCase类
  • 第三步:类中每一个方法代表一个测试用例,方法名必须以test开头
import unittest

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

class my_test(unittest.TestCase):
    def test_001(self):
        print(my_sum(5,6))

    def test_002(self):
        print(my_sum(0,3))

在这里插入图片描述

  • 如果鼠标右键不出现unittest选项,如下操作之后按下OK键
    在这里插入图片描述
    在这里插入图片描述

TestSuite

  • 把多个测试用例整合成一个测试套件
  • 使用方法
    • import导入unittest
    • import导入其他的包含测试用例的py文件
      • py文件的命名规则与变量名相同
    • 实例化unittest.TestSuite类的对象
    • 调用对象的addTest方法
      • addTest(py文件名.类名(“方法名”))
import unittest
import testcase_01

suite = unittest.TestSuite()    # 实例化
suite.addTest(testcase_01.my_test("test001"))
suite.addTest(testcase_01.my_test("test002"))
# 代码到这里只是把测试用例添加到了套件中,并不是执行测试用例
  • 用unittest.makeSuite一次导入一个类中的所有测试方法
import unittest
import testcase_01

suite = unittest.TestSuite()    # 实例化
# suite.addTest(testcase_01.my_test("test001"))
# suite.addTest(testcase_01.my_test("test002"))
# 代码到这里只是把测试用例添加到了套件中,并不是执行测试用例
suite.addTest(unittest.makeSuite(testcase_01.my_test))   # 一次性导入一个类中的所有测试方法

TextTestRunner

  • 作用:TextTestRunner是用来执行测试用例
  • 使用方法
    • 先实例化TextTestRunner的对象
    • 调用对象的run方法
      • 只要把suite作为参数,放入到run方法里面去
import unittest
import testcase_01

suite = unittest.TestSuite()    # 实例化
# suite.addTest(testcase_01.my_test("test001"))
# suite.addTest(testcase_01.my_test("test002"))
# 代码到这里只是把测试用例添加到了套件中,并不是执行测试用例
suite.addTest(unittest.makeSuite(testcase_01.my_test))   # 一次性导入一个类中的所有测试方法

runner = unittest.TextTestRunner()     # 实例化TextTestRunner的对象
runner.run(suite)    # 调用对象的run方法

TestLoader

  • 可以从指定目录查找指定py文件中的所有测试用例,自动加载到TestSuite中
import unittest
# 用TestLoader对象的discover方法来自动查找py,自动加载py文件中的方法
# 第一个参数是从哪里找py文件,“.”从当前目录开始查找py文件
# 第二个参数是指定py文件的文件名,可以用通配符
suite = unittest.TestLoader().discover(".","my*.py")
runner = unittest.TextTestRunner()
runner.run(suite)

TestSuite与TestLoader区别

  • TestSuite需要手动添加测试用例,可以添加测试类,也可以添加测试类中某个测试方法
    • 当要执行py文件中多个测试用例的几个,而不是全部执行,那么适合用TestSuite的addTest加载指定的测试用例
  • TestLoader搜索指定目录下指定开头.py文件,并添加测试类中的所有测试方法,不能指定添加测试方法
    • 当要执行py文件中的所有测试用例,适合使用TestLoader

小结

  • 所有的测试用例最终都是用TextTestRunner来执行的
  • TextTestRunner指定的是TestSuite
  • 一个TestSuite中可以有多个TestCase

Fixture

  • 可以在测试用例执行之前自动调用指定的函数,在测试用例执行之后自动调用指定的函数
  • 控制级别
    • 方法级
      • 每个方法执行前和执行后都自动调用函数
    • 类级
      • 不管类中有多少方法,一个类执行前后都自动调用函数
    • 模块级
      • 不管一个模块(一个模块就是一个py文件)中有多少类,模块执行前后自动调用函数

方法级

  • 在TestCase,也就是测试用例所在的class中定义方法
  • def setUp(self)当测试用例执行前,自动被调用
  • def tearDown(self)当测试用例执行后,自动被调用
  • 如果一个TestCase中有多个测试用例,那么setUp和tearDown就会被自动调用多次。mytest.py内容修改如下:
import unittest

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

class my_test(unittest.TestCase):
    def setUp(self):
        print("setUp被自动调用了")
    def tearDown(self):
        print("testDown被自动调用了")

    def test_001(self):
        print(my_sum(5,6))

    def test_002(self):
        print(my_sum(0,3))
        

类级

  • 不管类中有多少方法,一个类开始的时候自动调用函数,结束之后自动调用函数
  • 类级的fixture一定要是类方法
  • @classmethond def setUpClass(cls)类开始时自动调用的方法
  • @classmethond def tearDownClass(cls)类结束时自动调用的方法
  • mytest.py修改如下:
import unittest

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

class my_test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("setupclass自动调用了")
    @classmethod
    def tearDownClass(cls):
        print("tearDownClass自动调用了")
    def setUp(self):
        print("setUp被自动调用了")
    def tearDown(self):
        print("testDown被自动调用了")

    def test_001(self):
        print(my_sum(5,6))

    def test_002(self):
        print(my_sum(0,3))
        

模块级

  • 不管py文件中有多少个类,以及类中有多少方法,只自动执行一次
  • def setUpModule()在py文件开始时自动调用
  • def tearDownModule()在py文件结束时自动调用
  • mytest.py文件修改如下:
import unittest

def setUpModule():
    print("setUpModule自动调用了")

def tearDownModule():
    print("tearDwonModule自动调用了")

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

class my_test1(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("setupclass自动调用了")
    @classmethod
    def tearDownClass(cls):
        print("tearDownClass自动调用了")
    def setUp(self):
        print("setUp被自动调用了")
    def tearDown(self):
        print("testDown被自动调用了")

    def test_001(self):
        print(my_sum(5,6))

    def test_002(self):
        print(my_sum(0,3))


class my_test2(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("setupclass自动调用了")
    @classmethod
    def tearDownClass(cls):
        print("tearDownClass自动调用了")
    def setUp(self):
        print("setUp被自动调用了")
    def tearDown(self):
        print("testDown被自动调用了")

    def test_001(self):
        print(my_sum(5,6))

    def test_002(self):
        print(my_sum(0,3))

小结

  • 一定要在继承于unittest.TestCase这个类的子类中使用
  • setUp,tearDown,每个方法执行开始和完毕后自动调用
  • setUpClass,tearDwonClass,每个类开始时和结束时自动调用
  • setUpModule,tearDownModule,每个py文件开始和结束的时候自动调用

断言

  • 让程序来判断测试用例执行结果是否符合预期

UnitTest常用断言方法

  • assertEqual(参数1,参数2),参数顺序可以颠倒
    • 如果参数1(实际结果)参数2(预期结果)的值相同,断言成功没否则断言失败
    • 修改后的mytest.py:
import unittest

def setUpModule():
    print("setUpModule自动调用了")

def tearDownModule():
    print("tearDwonModule自动调用了")

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

class my_test1(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("setupclass自动调用了")
    @classmethod
    def tearDownClass(cls):
        print("tearDownClass自动调用了")
    def setUp(self):
        print("setUp被自动调用了")
    def tearDown(self):
        print("testDown被自动调用了")

    def test_001(self):
        num1 = print(my_sum(5,6))    #定义变量num1得到函数的返回值
        self.assertEqual(num1,11)    # num1存在实际结果,11时预期结果
        # 实际结果与预期结果相符,代表测试用例测试通过

    def test_002(self):
        num1 = print(my_sum(0,3))
        self.assertEqual(num1,3)

  • assertIn(参数1,参数2)
    • 如果参数1在参数2里面,则断言成功,否则断言失败。修改后的mytest.py如下:
import unittest
import random

def setUpModule():
    print("setUpModule自动调用了")

def tearDownModule():
    print("tearDwonModule自动调用了")

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

def my_rand():     # 返回1到5之间的随机数
    return random.randint(10,50)

class my_test1(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("setupclass自动调用了")
    @classmethod
    def tearDownClass(cls):
        print("tearDownClass自动调用了")
    def setUp(self):
        print("setUp被自动调用了")
    def tearDown(self):
        print("testDown被自动调用了")

    def test_001(self):
        num1 = my_sum(1,6)  #定义变量num1得到函数的返回值
        self.assertEqual(num1,7)    # num1存在实际结果,11时预期结果
        # 实际结果与预期结果相符,代表测试用例测试通过

    def test_002(self):
        num1 = my_sum(0,3)
        self.assertEqual(num1,3)

    def test_003(self):
        num1 = my_rand()
        self.assertIn(num1,[1,2,3,4,5])

测试用例中使用参数化的场景

  • 多个测试用例代码相同,只是测试数据和预期结果不同,可以把多个测试用例通过参数化技术合并为一个测试用例

参数化场景一

  • 第一步:导入from parameterized import parameterized
  • 第二步:在方法上面用 @parameterized.expand()修饰方法
    • expand()里面是一个列表
    • 列表里面放多个元组,每个元组中的成员就代表调用方法使用的实参
    • 列表中有几个元组,方法就会自动被调用几次
import unittest
from parameterized import parameterized

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

class my_test1(unittest.TestCase):

     # a是调用my_sum的第一个参数
     # b是调用my_sum的第一个参数
     # c是预期结果
    @parameterized.expand([(1,2,3),(5,7,11),(-1,3,2)])
    def test_001(self,a,b,c):
        num1 = my_sum(1,6)  #定义变量num1得到函数的返回值
        self.assertEqual(num1,7)    # num1存在实际结果,11是预期结果
        # 实际结果与预期结果相符,代表测试用例测试通过

参数化场景二

import unittest
from parameterized import parameterized

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

list1 = [(1,2,3),(5,7,11),(-1,3,2)]

class my_test1(unittest.TestCase):

     # a是调用my_sum的第一个参数
     # b是调用my_sum的第一个参数
     # c是预期结果
    @parameterized.expand(list1)
    def test_001(self,a,b,c):
        num1 = my_sum(1,6)  #定义变量num1得到函数的返回值
        self.assertEqual(num1,7)    # num1存在实际结果,11时预期结果
        # 实际结果与预期结果相符,代表测试用例测试通过

参数化场景三

import unittest
from parameterized import parameterized

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

def get_data():  #定义了一个函数,返回一个列表
    return [(1,2,3),(5,7,11),(-1,3,2)]

class my_test1(unittest.TestCase):

     # a是调用my_sum的第一个参数
     # b是调用my_sum的第一个参数
     # c是预期结果
    @parameterized.expand(get_data())
    def test_001(self,a,b,c):
        num1 = my_sum(1,6)  #定义变量num1得到函数的返回值
        self.assertEqual(num1,7)    # num1存在实际结果,11时预期结果
        # 实际结果与预期结果相符,代表测试用例测试通过

跳过

  • 可以通过@unittest.skip跳过指定的方法或函数
  • 语法:
@unitteat.skip
def 方法名():
 @unittest.skip
    def test_002(self):
        print("test002")

通过TextTestRunner生成测试报告

  • 在实例化TextTestRunner对象的时候,需要写参数
stream=file,verbosity=2
file代表用open打开的一个文件
verbosity=2,固定
  • 第一步:用open,w方式打开测试报告文件
  • 第二步,实例化TextTestRunner对象
  • 第三步:调用对象的run方法执行测试套件
  • 第四步:关闭open打开的文件
import unittest
# 用TestLoader对象的discover方法来自动查找py,自动加载py文件中的方法
# 第一个参数是从哪里找py文件,“.”从当前目录开始查找py文件
# 第二个参数是指定py文件的文件名,可以用通配符
suite = unittest.TestLoader().discover(".","my*.py")
# runner = unittest.TextTestRunner()
file = open("test01.txt","w",encoding="utf8")
runner = unittest.TextTestRunner(stream=file,verbosity=2)
runner.run(suite)
file.close()

HTML测试报告

  • 把文件HTMLTestRunner.py拷贝到项目目录下
  • 在代码中导入模块from HTMLTestRunner import HTMLTestRunner
  • 调用HTMLTestRunner(stream=file,title=“我的第一个html测试报告”)
    • 第一个参数是用open打开的文件,扩展名一定是.html
    • open打开文件的时候用wb,不用指定字符集
  • 调用runner对象的run方法执行测试套件
  • 关闭open打开的文件
import unittest
from HTMLTestRunner import HTMLTestRunner
# 用TestLoader对象的discover方法来自动查找py,自动加载py文件中的方法
# 第一个参数是从哪里找py文件,“.”从当前目录开始查找py文件
# 第二个参数是指定py文件的文件名,可以用通配符
suite = unittest.TestLoader().discover(".","my*.py")
# runner = unittest.TextTestRunner()
file = open("test01.html","wb")  # 用wb代表用二进制方式打开文件
# runner = unittest.TextTestRunner(stream=file,verbosity=2)
runner = HTMLTestRunner(stream=file,title="我的第一个html测试报告")
runner.run(suite)
file.close()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单元测试报告 版本:V1.3 文 档 编 号 保 密 等 级 作 者 最后修改日期 审 核 人 最后审批日期 批 准 人 最后批准日期 修订记录 日期 版本 修订说明 修订人 目 录 1 简介 2 1.1 目的 2 1.2 背景 2 1.3 范围 2 2 测试用例清单 2 3 功能测试分析 2 4 边界测试分析 2 5 覆盖率分析 2 6 内存使用分析 2 7 典型缺陷记录 3 7.1 缺陷1 3 7.1.1 表现 3 7.1.2 原因 3 7.1.3 方案 3 8 测试数据分析 3 8.1 测试有效性分析 3 8.2 测试效率分析 3 9 产品质量分析 4 10 测试结论 4 简介 目的 【描述该单元测试报告的目的。】 背景 【描述单元测试报告的背景,单元测试活动目的。如无特殊背景信息,可裁剪。】 范围 【说明该单元测试报告在整个项目周期的适用范围】 测试用例清单 模块 目标类 级别 用例类 用例描述 执行结果 备注 【被测的代码类】 【代码级别】 【Junit测试类1】 【意图描述】 【P/F】 【Junit测试类2】 功能测试分析 边界测试分析 覆盖率分析 目标类 级别 方法覆盖率 行覆盖率 备注 【被测的代码类】 【代码级别】 内存使用分析 典型缺陷记录 记录单元测试中所发现的典型缺陷或常见缺陷。供再次发现同类问题时,作为参考使用。 缺陷1 表现 【缺陷表现描述】 原因 【缺陷产生原因分析描述】 方案 【解决方案描述】 测试有效性分析 【统计实际发现的缺陷数据,分析与计划值产生偏差的原因,结合《项目量化管理计划》定义的阈值,确定是否采取相关措施】 计划发现缺陷数 致命 严重 一般 实际发现缺陷数 偏差分析 对策或调整措施 产品质量分析 【结合上述数据和信息,对本次测试的项目、产品的本身质量进行分析、评价和总结】 测试结论  【描述测试是否达到测试计划的目的,是否满足单元测试的结束条件。】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值