09 Python学习之UnitTest

简介: UnitTest 是 Python 自带的一个单元测试框架,用它来做单元测试。
UnitTest 是 Python 自带的一个单元测试框架,用它来做单元测试。

为什么使用UnitTest框架?

  • 能够组织多个用例去执行;
  • 提供丰富的断言方法;
  • 能够生成测试报告;

1、 UnitTest

UnitTest 核心要素

  1. TestCase;
  2. TestSuite;
  3. TestRunner;
  4. TestLoader;
  5. Fixture;

1.1 TestCase

TestCase 就是测试用例的意思。

示例:

我们可以定义一个实现加法操作的函数,并对该函数进行测试。

# 导包
import unittest


# 定义函数(方法)
def my_sum(i, j):
    return i + j;


# 定义测试类 注:必须继承unittest.TestCase
class my_test(unittest.TestCase):
    # 定义测试方法 注: 测试方法名称命名以 test 开头;
    def test_01(self):
        print(my_sum(1, 2))

    def test_02(self):
        print(my_sum(3, 4))

1.2 TestSuite

TestSuite 翻译过来的意识就是 测试套件,多条测试用例集合在一起,就是一个 TestSuite。

使用:

1、实例化(suite:为 TestSuite 实例化的名称,你可以叫a,b,c 都可以)

suite = unittest.TestSuite()

2、添加用例(ClassName:为类名;MethodName:为方法名)

suite.addTest(ClassName("MethodName"))

3、添加扩展:(搜索指定 ClassName 内 test 开头的方法并添加到测试套件中)

suite.addTest(unittest.makeSuite(ClassName))

注:

TestSuite 需要配合 TextTestRunner 才能被执行

1.3 TextTestRunner

TextTestRunner 是用来执行测试用例和测试套件的

使用:

  1. 实例化: runner = unittest.TextTestRunner()
  2. 执行: runner.run(suite) # suite:为测试套件名称

示例:

这里我们多写将测试类分模块。

Test01.py
# 导包
import unittest


# 定义函数(方法)
def my_sum(i, j):
    return i + j;


# 定义测试类 my_test 注:必须继承unittest.TestCase
class my_test(unittest.TestCase):
    # 定义测试方法 注: 测试方法名称命名以 test 开头;
    def test_01(self):
        print("结果:%s" % my_sum(1, 2)+" my_test的test_01")

    def test_02(self):
        print("结果:%s" % my_sum(3, 4)+" my_test的test_02")
Test02.py
# 导包
import unittest


# 定义函数(方法)
def my_sum(i, j):
    return i + j;


class my_test02(unittest.TestCase):
    def test_01(self):
        print("结果:%s" % my_sum(1, 2)+" my_test02的test_01")

    def test_02(self):
        print("结果:%s" % my_sum(1, 2)+" my_test02的test_02")
Test.py :执行测试用例
import unittest
import Test01
import Test02

# 实例化TestSuite
suite = unittest.TestSuite()
# 添加用例
suite.addTest(Test01.my_test("test_01"))
# 添加 my_test02 类中所有 test 开头的方法
suite.addTest(unittest.makeSuite(Test02.my_test02))
# 实例化TextTestRunner
runner = unittest.TextTestRunner()
# 执行
runner.run(suite)

1.4 TestLoader

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

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

使用:

suite = unittest.TestLoader().discover(test_dir, pattern='test*.py')
test_dir: 为指定的测试用例的目录;

pattern:为查找的.py 文件的格式;

注:

如果文件名默认为'test*.py' 也可以使用 unittest.defaultTestLoader 代替 unittest.TestLoader()

示例:

import unittest

# 实例化 TestLoader
suite = unittest.TestLoader().discover("./", "test0*.py")
# 实例化TextTestRunner
runner = unittest.TextTestRunner()
# 执行
runner.run(suite)

TestSuite TestLoader 区别

  • TestSuite 需要手动添加测试用例(可以添加测试类,也可以添加测试类中某个测试方法);
  • TestLoader 搜索指定目录下指定开头.py 文件,并添加测试类中的所有的测试方法,不能指定添加测试方法;

2、Fixture

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

Fixture有三个控制级别:

2.1 方法级别

在TestCase,也就是测试用例所在的class中定义方法,如果一个TestCase中有多个测试用例,那么setUp和tearDown就会被自动调用多次。

使用:

  • 初始化(前置处理): def setUp(self) --> 首先自动执行;
  • 销毁(后置处理): def tearDown(self) --> 最后自动执行;

运行于测试方法的始末,即:运行一次测试方法就会运行一次 setUp 和tearDown

示例:

# 导包
import unittest


# 定义函数(方法)
def my_sum(i, j):
    return i + j;


# 定义测试类 my_test 注:必须继承unittest.TestCase
class my_test(unittest.TestCase):
    # 初始化方法
    def setUp(self):
        print("setUP 执行初始化")

    # 销毁方法
    def tearDown(self):
        print("tearDown 执行销毁")

    # 定义测试方法 注: 测试方法名称命名以 test 开头;
    def test_01(self):
        print("结果:%s" % my_sum(1, 2) + " my_test的test_01")

    def test_02(self):
        print("结果:%s" % my_sum(3, 4) + " my_test的test_02")

2.2 类级别

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

使用:

  • 初始化(前置处理): @classmethod def setUpClass(cls): --> 首先自动执行

    • 销毁(后置处理): @classmethod def tearDownClass(cls): --> 最后自动执行

运 行于 测试 类的 始末 , 即: 每个 测试类只会运行 一次 setUpClass 和 tearDownClass

# 导包
import unittest


# 定义函数(方法)
def my_sum(i, j):
    return i + j;


# 定义测试类 my_test 注:必须继承unittest.TestCase
class my_test(unittest.TestCase):
    # 初始化
    @classmethod
    def setUpClass(cls):
        print("setUP 执行初始化")

    # 销毁方法
    @classmethod
    def tearDownClass(cls):
        print("tearDown 执行销毁")

    # 定义测试方法 注: 测试方法名称命名以 test 开头;
    def test_01(self):
        print("结果:%s" % my_sum(1, 2) + " my_test的test_01")

    def test_02(self):
        print("结果:%s" % my_sum(3, 4) + " my_test的test_02")

2.3 模块级别

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

使用:

  • 初始化(前置处理): def setUpModule(): --> 首先自动执行
  • 销毁(后置处理): def tearDownModule(): --> 最后自动执行
# 导包
import unittest


# 定义函数(方法)
def my_sum(i, j):
    return i + j;


# 模块级
def setUpModule():
    print("setUpModule自动调用了")


# 模块级
def tearDownModule():
    print("tearDownModule自动调用了")


# 定义测试类 my_test 注:必须继承unittest.TestCase
class my_test(unittest.TestCase):
    # 定义测试方法 注: 测试方法名称命名以 test 开头;
    def test_01(self):
        print("结果:%s" % my_sum(1, 2) + " my_test的test_01")

    def test_02(self):
        print("结果:%s" % my_sum(3, 4) + " my_test的test_02")


# 定义测试类 my_test02
class my_test02(unittest.TestCase):
    def test_01(self):
        print("结果:%s" % my_sum(1, 2) + " my_test02的test_01")

    def test_02(self):
        print("结果:%s" % my_sum(1, 2) + " my_test02的test_02")

2.4 总结

  • 必须继承 unittest.TestCase 类,setUp、tearDown 才是一个 Fixture;
  • 方法级:setUp,tearDown:如果一个类中有多个测试用例,每执行一个测试用例之前会调用一次 setUp,之后会调用一次 tearDown;
  • 类级:setUpClass,tearDownClass:如果一个类中有多个测试用例,执行所有测试用例之前只会调用一次 setUpClass,之后只会调用一次 tearDownClass;
  • 模块级:setUpModule,tearDownModule:只在 import 导入这个模块时会调用一次 setUpModule,模块使用完成之后会调用一次 tearDownModule;
  • setUpXXX:一般做初始化工作; tearDownXXX:一般做结束工作;

3、断言

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

为什么要学习断言呢?

因为自动化脚本在执行的时候一般都是无人值守状态,我们不知道执行结果是否符合预期结果,所以我们需要让 程序代替 人为检测程序执行的结果是否符合预期结果,这就需要使用断言。

3.1 UnitTest 常用断言方法

UnitTest 中提供了非常丰富的断言方法,复杂的断言方法在自动化测试中几乎使用不到,所以我们只需要掌握几个常用的即可。

常用的 UnitTest 断言方法:

序号 断言方法 断言描述
1 assertTrue(expr, msg=None) 验证 expr 是 true,如果为 false,则 fail
2 assertFalse(expr, msg=None) 验证 expr 是 false,如果为 true,则 fail
3 assertEqual(expected, actual, msg=None) 验证 expected==actual,不等则 fail
4 assertNotEqual(first, second, msg=None) 验证 first != second, 相等则 fail
5 assertIsNone(obj, msg=None) 验证 obj 是 None,不是则 fail
6 assertIsNotNone(obj, msg=None) 验证 obj 不是 None,是则 fail
7 assertIn(member, container, msg=None) 验证是否 member in container
8 assertNotIn(member, container, msg=None) 验证是否 member not in container

3.2 使用方式

断言方法已经在 unittest.TestCase 类中定义好了,而且我们自定义的测试类已经继承了 TestCase,所以在测试方法中直接调用即可。
# 导包
import unittest


# 定义函数(方法)
def my_sum(i, j):
    return i + j;


# 定义测试类 my_test 注:必须继承unittest.TestCase
class my_test(unittest.TestCase):
    # 定义测试方法 注: 测试方法名称命名以 test 开头;
    def test_01(self):
        num = my_sum(1, 2)
        # 如果 num为4,正确
        self.assertEqual(3, num);

    def test_02(self):
        num = my_sum(3, 4)
        # 如果 num为7,正确
        self.assertEqual(7, num);

    def test_03(self):
        num = my_sum(1, 2)
        # 如果 num在列表中,正确
        self.assertIn(num,[1,2,3,4,5])

4、参数化

上面的测试用例都存在一个问题,都是一条测试数据定义一个测试函数,代码冗余度太高。

我们可以通过参数化的方式来传递数据,从而实现数据和脚本分离。

并且可以实现用例的重复执行。unittest测试框架,本身不支持参数化,但是可以通过安装 unittest扩展插件 parameterized 来实现。

4.1 安装 类库

方式一:

我们可以直接打开命令提示符输入:pip install parameterized

方式二 :

使用PyCharm 安装,直接看图

4.2 使用

方式一:

import unittest
from parameterized import parameterized


def my_sum(i, j):
    return i + j


class my_test(unittest.TestCase):
    # a是调用my_sum的第一个参数
    # b是调用my_sum的第二个参数
    # c是预期结果
    @parameterized.expand([(1, 2, 3), (5, 6, 110), (-1, 3, 2)])
    def test_001(self, i, j, k):
        # 定义变量num得到my_sum函数的返回值
        num = my_sum(i, j)
        # num1里存放的是实际结果,k是预期结果
        self.assertEqual(num, k)
        # 实际结果与预期结果相符,代表测试用例测试通过
        # 不相符代表测试用例测试失败

方式二:

就是直接定义好一个列表,列表里面有元组。

方式三:

就是定义一个函数(方法),然后直接返回元组。

5、跳过

对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行。

使用方式:

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

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

示例:

6、生成HTML测试报告

HTML 测试报告就是执行完测试用例后,以 HTML(网页)方式将执行结果生成报告。

为什么要生产测试报告?

因为测试报告是本次测试结果的体现形态,然后测试报告内包含了有关本次测试用例的详情;

HTML 生成报告方式

一种是TextTestRunner (UnitTest 自带),另外的就是其他的第三方模板HTMLTestRunner。

首先我们先来看看TextTestRunner如何生成测试报告的。

import unittest

# 生成测试套件
suite = unittest.TestLoader().discover("./", "test0*.py")
# 以只写方式打开测试报告文件
f = open("C:/Users/jie/Desktop/test.txt", "w", encoding="utf-8")
# 实例化TextTestRunner stream为open函数打开的文件流; verbosity 为不同模板编号
runner = unittest.TextTestRunner(stream=f,verbosity=2)
# 执行
runner.run(suite)
# 关闭
f.close()

结果

我们再来看看HTMLTestRunner 测试报告

首先要安装HTMLTestRunner,这里要注意的是由于HTMLTestRunner是一个第三方的unittest HTML报告库,用pip是死活安装不了的,得去网上下载HTMLTestRunner.py放到存放python源代码的Lib目录下。大家也可以用我下好的。

https://gitee.com/boring-yingjie/htmltest-runner.git

import unittest
from HTMLTestRunner import HTMLTestRunner

# 生成测试套件
suite = unittest.TestLoader().discover("./", "test*.py")
# 以只写方式打开测试报告文件
f = open("C:/Users/jie/Desktop/test01.html", "wb")
# 实例化 HTMLTestRunner 对象  stream:open 函数打开的文件流; title:[可选参数],为报告标题; description:[可选参数],为报告描述信息;比如操作系统、浏览器等版本;
runner = HTMLTestRunner(stream=f, title="自动化测试报告", description="Chrome 浏览器")
# 执行
runner.run(suite)
# 关闭
f.close()

效果

相关文章
|
2月前
|
机器学习/深度学习 前端开发 算法
学习Python需要多久?
【7月更文挑战第6天】学习Python需要多久?
64 5
|
1月前
|
程序员 测试技术 开发工具
豆瓣评分7.9!世界级讲师耗时5年整理出的Python学习手册!
Python是一门流行的开源编程语言,广泛用于各个领域的独立程序与脚本化应用中。它不仅免费、可移植、功能强大,同时相对简单,而且使用起来充满乐趣。从软件业界的任意一角到来的程序员,都会发现Python着眼于开发者的生产效率以及软件质量,因此无论你的项目是大还是小,选择Python都将带来战略性的优势。 今天给小伙伴们分享的这份手册讲述了完整的Python语言,力争满足“语言”和“原理”两个方面的需求,并拥有足够的深度以便实用。废话不多说,下面展示给大家。
|
1月前
|
数据采集 数据可视化 Ruby
GitHub星标破万!Python学习教程(超详细),真的太强了!
Python 是一门初学者友好的编程语言,想要完全掌握它,你不必花上太多的时间和精力。 Python 的设计哲学之一就是简单易学,体现在两个方面: 1. 语法简洁明了:相对 Ruby 和 Perl,它的语法特性不多不少,大多数都很简单直接,不玩儿玄学。 2. 切入点很多:Python 可以让你可以做很多事情,科学计算和数据分析、爬虫、Web 网站、游戏、命令行实用工具等等等等,总有一个是你感兴趣并且愿意投入时间的。
|
1月前
|
机器学习/深度学习 开发者 Python
Python 与 R 在机器学习入门中的学习曲线差异
【8月更文第6天】在机器学习领域,Python 和 R 是两种非常流行的编程语言。Python 以其简洁的语法和广泛的社区支持著称,而 R 则以其强大的统计功能和数据分析能力受到青睐。本文将探讨这两种语言在机器学习入门阶段的学习曲线差异,并通过构建一个简单的线性回归模型来比较它们的体验。
49 7
|
1月前
|
JSON API 开发者
Python学习Get方式通过商品 ID请求 获取拼多多商品详情数据接口
拼多多商品详情数据接口服务使开发者或商家能编程获取平台商品详情,涵盖标题、价格、销量等关键信息,助力市场分析与决策。使用前需注册开发者账号并获取API密钥;构造含商品ID等参数的请求URL后发送至API服务器;接口以JSON格式返回数据。应用场景包括商品销售分析、选品、品牌口碑挖掘及竞品分析,为商家提供强大数据支持。
|
1月前
|
算法 数据挖掘 大数据
深入学习Python的性能优化
【8月更文挑战第9天】深入学习Python性能优化涵盖设定明确目标、运用timeit与cProfile等工具诊断瓶颈、优化代码结构与算法、采用并行/并发技术、利用生成器与第三方库等策略。这是一个持续学习的过程,旨在全面提升代码效率与响应速度。
29 1
|
2月前
|
机器学习/深度学习 搜索推荐 TensorFlow
使用Python实现深度学习模型:智能教育与个性化学习
【7月更文挑战第29天】 使用Python实现深度学习模型:智能教育与个性化学习
121 9
|
1月前
|
数据采集 人工智能 数据可视化
【2023年电工杯竞赛】B题 人工智能对大学生学习影响的评价 数学建模方案和python代码
本文介绍了2023年电工杯竞赛B题的数学建模方案和Python代码实现,详细阐述了如何分析调查问卷数据,建立评价指标体系,构建数学模型评估人工智能对大学生学习的影响,并提供了数据预处理、特征编码、可视化分析等代码示例。
39 0
【2023年电工杯竞赛】B题 人工智能对大学生学习影响的评价 数学建模方案和python代码
|
1月前
|
存储 JSON 测试技术
Python中最值得学习的第三方JSON库
Python中最值得学习的第三方JSON库
|
1月前
|
机器学习/深度学习 人工智能 TensorFlow
神经网络不再是黑魔法!Python带你一步步拆解,让AI学习看得见
【8月更文挑战第3天】神经网络,曾被视为难以触及的黑魔法,现已在Python的助力下变得平易近人。以TensorFlow或PyTorch为“魔法杖”,仅需几行Python代码即可构建强大的AI模型。从零开始,我们将教导AI识别手写数字,利用经典的MNIST数据集。通过数据加载、预处理至模型训练与评估,每个步骤都如精心编排的舞蹈般清晰可见。随着训练深入,AI逐渐学会辨认每个数字,其学习过程直观展现。这不仅揭示了神经网络的奥秘,更证明了任何人都能借助Python创造AI奇迹,共同探索未来的无限可能。
36 2