首页 > 编程语言 >Python 单元测试详解:Unittest 框架的应用与最佳实践

Python 单元测试详解:Unittest 框架的应用与最佳实践

时间:2024-09-19 09:51:48浏览次数:3  
标签:func1 Python Unittest 单元测试 test assertEqual unittest my self

Python 单元测试详解:Unittest 框架的应用与最佳实践

文章目录

本文介绍了如何使用 Python 的原生测试框架 Unittest 进行单元测试,从基础的测试编写到复杂的场景覆盖。首先,展示了如何在不使用测试框架的情况下手动调试代码,并对比了使用 Unittest 的好处。文章通过多个实际示例,介绍了如何编写测试用例、处理断言和异常、分离测试文件以及执行多功能测试。同时,探讨了 Unittest 提供的常用断言方法,并展示了如何单独测试某个功能。最后,总结了编写高效单元测试的建议,使开发者在项目中更好地保证代码质量。

一 什么是 Unittest

unittest 是 Python 原生的测试框架。

1 不使用 Unittest 测试框架
def my_div(a, b):
    return a / b
# ZeroDivisionError: division by zero
my_div(1, 0)

程序抛出错误。不用测试框架手动运行调试,即边开发边调试,这种方式比较适合以下场景。

  • 项目整体规模较小
  • 项目功能数量较少
  • 项目功能之间相对独立
2 使用 Unittest 测试框架

TestFunc 继承 unittest.TestCase ,使用 unittest.main() 调用单元测试就写好了。

以下是运行没问题的单元测试。

# TestFunc 继承 unittest.TestCase
class TestFunc(unittest.TestCase):
    def test_div(self):
        # 运行之后 OK
        self.assertEqual(2, my_div(2, 1))
        self.assertEqual(-2, my_div(2, -1))

if __name__ == '__main__':
    print_hi('单元测试')
    unittest.main()

# 运行之后
# Ran 1 test in 0.000s

# OK

以下是运行抛异常的单元测试。

# TestFunc 继承 unittest.TestCase
class TestFunc02(unittest.TestCase):
    def test_div(self):
        # 这里后面我填了一个 1 纯粹是为了占一个位置,2/0 != 1,你知道的,
        # 后面我们再介绍更优雅的写法
        # 运行之后 FAILED (errors=1)
        self.assertEqual(1, my_div(2, 0))

if __name__ == '__main__':
    print_hi('单元测试')
    unittest.main()
    
# 运行之后 FAILED (errors=1)

二 unittest 使用建议

假如要开发一个:输入 1 返回 2,输入 - 1 返回 3 ,输入其他任何数,返回 1 的程序。

1 先写测试 case 后写测试逻辑

建议先写 unittest 当中的 case,再写你要封装的函数 my_func03。

def my_func03(a):
    # 逻辑先空在这里
    return None

class TestFunc03(unittest.TestCase):
     def test_func(self):
         self.assertEqual(2, my_func03(1))
         self.assertEqual(3, my_func03(-1))
         for i in range(-100, 100):
             if i == 1 or i == -1:
                 continue
             self.assertEqual(1, my_func03(i))
2 测试文件以 _test.py 结尾

建议一个 py 文件一个 test ,比如文件是 yourpython.py ,则单元测试可以命名为 yourpython_test.py

三 多个功能测试

一个类 TestFunc04 中定义多个测试函数。

def my_func1(a):
    if a == 1:
        return 2
    elif a == -1:
        return 3
    else:
        return 1


def my_func2(b):
    if b != "yes":
        raise ValueError("you can only say yes!")
    else:
        return True


class TestFunc04(unittest.TestCase):
    def test_func1(self):
        self.assertEqual(2, my_func1(1))
        self.assertEqual(3, my_func1(-1))
        for i in range(-100, 100):
            if i == 1 or i == -1:
                continue
            self.assertEqual(1, my_func1(i))

    def test_func2(self):
        self.assertTrue(my_func2("yes"))
        with self.assertRaises(ValueError):
            my_func2("nononono")

四 用 Python 命令执行测试

$ python -m unittest 单元测试.py

五 断言 assert 常用方法

在 unittest 的模块中有很多丰富的测试方法函数。

assert 断言含义
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(condition)condition 是不是 True
assertFalse(condition)condition 是不是 False
assertGreater(a, b)a > b
assertGreaterThan(a, b)a >= b
assertLess(a, b)a < b
assertLessEqual(a, b)a <= b
assertIs(a, b)a is b,a 和 b 是不是同一对象
assertIsNot(a, b)a is not b,a 和 b 是不是不同对象
assertIsNone(a)a is None,a 是不是 None
assertIsNotNone(a)a is not None,a 不是 None?
assertIn(a, b)a in b, a 在 b 里面?
assertNotIn(a, b)a not in b,a 不在 b 里?
assertRaises(err)通常和 with 一起用,判断 with 里的功能是否会报错(上面练习有用到过)

六 测试单独的功能

测试类 TestFunc05 中的 test_func1 方法。常用的两种方式。

1 第一种

使用 TestSuite() 和 TextTestRunner()

# 第一种,使用 TestSuite() 和 TextTestRunner()
class TestFunc05(unittest.TestCase):
    def test_func1(self):
        self.assertEqual(2, my_func1(1))
        self.assertEqual(3, my_func1(-1))
        for i in range(-100, 100):
            if i == 1 or i == -1:
                continue
            self.assertEqual(1, my_func1(i))

    def test_func2(self):
        self.assertTrue(my_func2("yes"))
        with self.assertRaises(ValueError):
            my_func2("nononono")


# 定义一个 suite 替换 unittest.main()
suite = unittest.TestSuite()
suite.addTest(TestFunc04('test_func1'))
unittest.TextTestRunner().run(suite)
2 第二种
# 第二种,Python 的命令来执行不同的 test
$ python -m unittest 单元测试.TestFunc05.test_func1
$ python -m unittest 单元测试.TestFunc05.test_func2

七 完整代码示例

# This is a sample Python script.
import unittest


# Press ⌃R to execute it or replace it with your code.
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.


def print_hi(name):
    # Use a breakpoint in the code line below to debug your script.
    print(f'Hi, {name}')  # Press ⌘F8 to toggle the breakpoint.

    # 什么是 Unittest

    # 不用 Unittest 单元测试,可能是先运行试试
    # ZeroDivisionError: division by zero
    # 这种方式比较适合
    # 小型项目,
    # 没有多少个功能的项目,
    # 而且项目功能之间并不会有任何联系。
    # my_div(1, 0)


def my_div(a, b):
    return a / b

    # 使用 unittest

    # TestFunc 继承 unittest.TestCase
    # class TestFunc(unittest.TestCase):
    #     def test_div(self):
    #         # 运行之后 OK
    #         self.assertEqual(2, my_div(2, 1))
    #         self.assertEqual(-2, my_div(2, -1))

    # class TestFunc02(unittest.TestCase):
    #     def test_div(self):
    #         # 这里后面我填了一个 1 纯粹是为了占一个位置,2/0 != 1,你知道的,
    #         # 后面我们再介绍更优雅的写法
    #         # 运行之后 FAILED (errors=1)
    #         self.assertEqual(1, my_div(2, 0))

    unittest.main()

    # unittest 规范
    # 假如要开发一个:输入 1 返回 2,输入 - 1 返回 3 ,输入其他任何数,返回 1 的程序
    # 建议先写 unittest 当中的 case,再写你要封装的函数 my_func03


def my_func03(a):
    # 逻辑先空在这里
    return None


# class TestFunc03(unittest.TestCase):
#     def test_func(self):
#         self.assertEqual(2, my_func03(1))
#         self.assertEqual(3, my_func03(-1))
#         for i in range(-100, 100):
#             if i == 1 or i == -1:
#                 continue
#             self.assertEqual(1, my_func03(i))
# 建议一个 py 文件一个 test ,比如文件是 yourpython.py ,则单元测试可以命名为 yourpython_test.py


# 有时候要测试多个功能
def my_func1(a):
    if a == 1:
        return 2
    elif a == -1:
        return 3
    else:
        return 1


def my_func2(b):
    if b != "yes":
        raise ValueError("you can only say yes!")
    else:
        return True


class TestFunc04(unittest.TestCase):
    def test_func1(self):
        self.assertEqual(2, my_func1(1))
        self.assertEqual(3, my_func1(-1))
        for i in range(-100, 100):
            if i == 1 or i == -1:
                continue
            self.assertEqual(1, my_func1(i))

    def test_func2(self):
        self.assertTrue(my_func2("yes"))
        with self.assertRaises(ValueError):
            my_func2("nononono")

    # 用 Python 命令执行测试
    # python -m unittest 单元测试.py

    # 能测哪些 assert,在 unittest 的模块中有特别丰富的测试方式,常用的方法
    # 。。。


# 想测单独的功能
# 第一种,使用 TestSuite() 和 TextTestRunner()
class TestFunc05(unittest.TestCase):
    def test_func1(self):
        self.assertEqual(2, my_func1(1))
        self.assertEqual(3, my_func1(-1))
        for i in range(-100, 100):
            if i == 1 or i == -1:
                continue
            self.assertEqual(1, my_func1(i))

    def test_func2(self):
        self.assertTrue(my_func2("yes"))
        with self.assertRaises(ValueError):
            my_func2("nononono")


# 定义一个 suite 替换 unittest.main()
suite = unittest.TestSuite()
suite.addTest(TestFunc04('test_func1'))
unittest.TextTestRunner().run(suite)

# 第二种,Python 的命令来执行不同的 test
# python -m unittest 单元测试.TestFunc05.test_func2
# python -m unittest 单元测试.TestFunc05.test_func1

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    print_hi('单元测试')

# See PyCharm help at https://www.jetbrains.com/help/pycharm/

复制粘贴并覆盖到你的 main.py 中运行,运行结果如下。

Testing started at 16:02 ...
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK


Ran 4 tests in 0.001s

OK

八 源码地址

代码地址:

国内看 Gitee单元测试.py

国外看 GitHub单元测试.py

引用 莫烦 Python

标签:func1,Python,Unittest,单元测试,test,assertEqual,unittest,my,self
From: https://blog.csdn.net/u014394049/article/details/142303705

相关文章

  • Python 异常控制详解:try-except 的应用与多种异常处理策略
    Python异常控制详解:try-except的应用与多种异常处理策略文章目录Python异常控制详解:try-except的应用与多种异常处理策略一可遇见的异常二处理多个异常1多个异常一起处理2多个异常分开处理三try-except-else四try-except-finally五raise手动抛出异常六Pyt......
  • [Python数据可视化] Plotly:交互式数据可视化的强大工具
    引言:在数据分析和可视化的世界中,Plotly是一颗耀眼的明星。它是一个开源的交互式图表库,支持多种编程语言,包括Python、R和JavaScript。Plotly的强大之处在于它能够创建出既美观又具有高度交互性的图表,使得数据探索和分析变得更加直观和有趣。本文将详细介绍Plotly的功能,......
  • python 深度神经网络训练,pytorch ,tensorflow paddle大模型训练中损失突然增大的原因
    在机器学习和深度学习的训练过程中,损失函数的数值突然变高可能是由多种因素引起的。以下是一些可能的原因和相应的解决方案:1.**学习率设置不当**:如果学习率过高,可能会导致模型在优化过程中跳过最小值,甚至导致模型发散。相反,如果学习率过低,则可能导致模型训练速度过慢,甚至停滞......
  • Python用TOPSIS熵权法重构粮食系统及期刊指标权重多属性决策MCDM研究|附数据代码
    原文链接:https://tecdat.cn/?p=37724原文出处:拓端数据部落公众号 分析师:SikunChen在当今世界,粮食系统的稳定性至关重要。尽管现有的全球粮食系统在生产和分配方面表现出较高的效率,但仍存在大量人口遭受饥饿以及诸多粮食安全隐患。与此同时,在学术领域,准确评估情报学期刊的质......
  • Python中的元类:掌握类的创建与定制
    在面向对象编程中,类是组织代码的重要手段。但在Python中,类本身也是对象,这意味着它们可以被创建、修改甚至定制。元类(Metaclass)是Python中的一种高级特性,它允许你在类被创建时对其进行修改或增强。本文将带你深入了解元类的概念、作用以及如何在实践中使用元类。元类是什么......
  • python爬虫连载22
    XPath运算符XPath运算符XPath运算符表达式可以返回节点集、字符串、逻辑值、数字。运算符描述实例含义|计算两个节点集//student/name|//student/age选取student元素的所有      name和age元素+加法/classroom/student[age=19+1]选取classroom元素的所有student元素,且......
  • python毕业设计基于django+vue软件技术代码分享交流平台设计与实现
    目录技术栈和环境说明预期达到的目标具体实现截图系统设计Python技术介绍django框架介绍flask框架介绍解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示操作可行性技术路线感恩大学老师和同学详细视频演示源码获取......
  • python毕业设计基于django+vue的考务管理系统的设计与实现
    目录技术栈和环境说明预期达到的目标具体实现截图系统设计Python技术介绍django框架介绍flask框架介绍解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示操作可行性技术路线感恩大学老师和同学详细视频演示源码获取......
  • D11【python接口自动化学习】-python基础之内置数据类型
    day11列表的常见操作学习日期:20240918学习目标:内置数据类型--20列表的常见操作学习笔记:添加元素#创建列表list_demo=['a','b','c','d']print(type(list_demo))#<class'list'>print(list_demo)#['a','b','c�......
  • 02. Python基础知识
    一、注释  在开发程序过程中,如果一段代码的逻辑比较复杂,不是特别容易理解,可以适当添加注释,以辅助自己或其他开发人员解读代码。注释是给程序员看的,为了让程序员方便阅读代码,解释器会忽略注释。在Pyton中,注释分为单行注释和多行注释。单行注释:在Python中,使用“#”作为单......