python基础8 单元测试

通过前面的7个章节,作者学习了python的各项基础知识,也学习了python的编译和执行。但在实际环境上,我们需要验证我们的代码功能符合我们的设计预期,所以需要结合python的单元测试类,编写单元测试代码。

Python有一个内置的unittest模块,我们可以使用它来进行单元测试。

基础用法

基本流程:

  1. 新建类,继承自unittest.TestCase
  2. 类的成员函数统一用test_开头,否则会无法识别和执行
  3. 通过调用unittest.main()来执行测试用例

简单的示例程序如下:

python 复制代码
import unittest

#新建类,继承自unittest.TestCase
#类的成员函数统一用test_开头,否则会无法识别和执行
#通过调用unittest.main()来执行测试用例

class TestMath(unittest.TestCase):
    def test_add(self):
        self.assertEqual(1 + 1, 2)

    def test_subtract(self):
        self.assertEqual(3 - 2, 1)

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

结果输出如下:

python 复制代码
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

测试函数和类方法

对函数的单元测试:

python 复制代码
import unittest

#定义测试用的函数
def add(v1,v2):
    return v1+v2

def subtract(v1,v2):
    return v1-v2

class TestMath(unittest.TestCase):
    def test_add(self):
        #测试用例实现对函数的调用
        self.assertEqual(add(1, 1), 2)

    def test_subtract(self):
        #测试用例实现对函数的调用
        self.assertEqual(subtract(2, 3), -1)

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

结果输出:

python 复制代码
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

对类的单元测试:

在下面示例中,我们对函数和复用的Car类同时进行了单元测试。

python 复制代码
import unittest

#定义测试用的函数
def add(v1,v2):
    return v1+v2

def subtract(v1,v2):
    return v1-v2

#复用前期定义的Car类
class Car(object):
    __slots__ = ('_color', '_number')

    @property
    def color(self):
        return self._color
    
    @color.setter
    def color(self,value):
        self._color = value

    @property
    def number(self):
        return self._number
    
    @number.setter
    def number(self,value):
        self._number = value
    
    @number.deleter
    def number(self):
        print('oops! number is deleted!')
    
    def func(self):
        print('car number: %d' %  self._number)
    pass

class TestAll(unittest.TestCase):
    def test_add(self):
        #测试用例实现对函数的调用
        self.assertEqual(add(1, 1), 2)

    def test_subtract(self):
        #测试用例实现对函数的调用
        self.assertEqual(subtract(2, 3), -1)

    def test_car_color(self):
        car = Car()
        car.color ="blue"
        self.assertEqual(car.color, "blue")

    #属性测试
    def test_car_property(self):
        car = Car()
        with self.assertRaises(AttributeError):
            value = car.engine
  

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

结果输出:

python 复制代码
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

测试套件和测试运行器

继承自unittest.TestCase的类,用test_开头的成员函数,可以称为一个测试用例。

使用测试套件的方法,可以自由的执行这些测试用例。如执行先后次序,部分执行等。

示例代码如下:

python 复制代码
import unittest

#定义测试用的函数
def add(v1,v2):
    return v1+v2

def subtract(v1,v2):
    return v1-v2

#复用前期定义的Car类
class Car(object):
    __slots__ = ('_color', '_number')

    @property
    def color(self):
        return self._color
    
    @color.setter
    def color(self,value):
        self._color = value

    @property
    def number(self):
        return self._number
    
    @number.setter
    def number(self,value):
        self._number = value
    
    @number.deleter
    def number(self):
        print('oops! number is deleted!')
    
    def func(self):
        print('car number: %d' %  self._number)
    pass

class TestAll(unittest.TestCase):
    def test_add(self):
        #测试用例实现对函数的调用
        self.assertEqual(add(1, 1), 2)

    def test_subtract(self):
        #测试用例实现对函数的调用
        self.assertEqual(subtract(2, 3), -1)

    def test_car_color(self):
        car = Car()
        car.color ="blue"
        self.assertEqual(car.color, "blue")

    #属性测试
    def test_car_property(self):
        car = Car()
        with self.assertRaises(AttributeError):
            value = car.engine
  

if __name__ == '__main__':
    # 创建测试套件
    suite = unittest.TestSuite()
    suite.addTest(TestAll('test_add'))
    #suite.addTest(TestAll('test_subtract'))
    suite.addTest(TestAll('test_car_property'))

    # 创建测试运行器
    runner = unittest.TextTestRunner()
    runner.run(suite) 

    # 通过执行结果,我们可以看到仅执行了我们添加的两个测试用例

测试准备和清理

很多时候,我们在测试用例执行之前,需要做一些准备操作,如执行数据库相关测试用例之前,需要进行数据库连接;之后需要断开数据库连接。这种场景下,我们需要使用python单元测试类默认的setUp和tearDown方法。修改上面的代码,并测试。

python 复制代码
import unittest

#定义测试用的函数
def add(v1,v2):
    return v1+v2

def subtract(v1,v2):
    return v1-v2

#复用前期定义的Car类
class Car(object):
    __slots__ = ('_color', '_number')

    @property
    def color(self):
        return self._color
    
    @color.setter
    def color(self,value):
        self._color = value

    @property
    def number(self):
        return self._number
    
    @number.setter
    def number(self,value):
        self._number = value
    
    @number.deleter
    def number(self):
        print('oops! number is deleted!')
    
    def func(self):
        print('car number: %d' %  self._number)
    pass

class TestAll(unittest.TestCase):
    def setUp(self):
        # 准备工作
        print("准备工作完成")
    
    def tearDown(self):
        # 结束后的工作
        print("结束清理工作完成")

    def test_add(self):
        #测试用例实现对函数的调用
        self.assertEqual(add(1, 1), 2)

    def test_subtract(self):
        #测试用例实现对函数的调用
        self.assertEqual(subtract(2, 3), -1)

    def test_car_color(self):
        car = Car()
        car.color ="blue"
        self.assertEqual(car.color, "blue")

    #属性测试
    def test_car_property(self):
        car = Car()
        with self.assertRaises(AttributeError):
            value = car.engine
  

if __name__ == '__main__':
    # 创建测试套件
    suite = unittest.TestSuite()
    suite.addTest(TestAll('test_add'))
    #suite.addTest(TestAll('test_subtract'))
    suite.addTest(TestAll('test_car_property'))

    # 创建测试运行器
    runner = unittest.TextTestRunner()
    runner.run(suite)

结果输出:

python 复制代码
准备工作完成
结束清理工作完成
.准备工作完成
结束清理工作完成
.
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

高级测试用法

条件测试

可以使用@unittest.skip关键字,来表示测试用例只有在满足特定条件下才执行。下面的示例中,我们使用关键字实现了一直跳过和条件跳过的功能。

@unittest.skip(reason)

Unconditionally skip the decorated test. reason should describe why the test is being skipped.

无条件跳过,需要输入填过的原因。

复制代码
   @unittest.skip("Always skip!")

@unittest.skipIf(condition , reason)

Skip the decorated test if condition is true.

条件满足时跳过。

python 复制代码
@unittest.skipIf(mylib.__version__ < (1, 3),
                     "not supported in this library version")

@unittest.skipUnless(condition , reason)

Skip the decorated test unless condition is true.

除此条件外,跳过。

python 复制代码
    @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")

@unittest.expectedFailure

Mark the test as an expected failure or error. If the test fails or errors in the test function itself (rather than in one of the test fixture methods) then it will be considered a success. If the test passes, it will be considered a failure.

失败时,测试用例返回成功。

python 复制代码
    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 0, "failed test")

exception unittest.SkipTest(reason)

This exception is raised to skip a test.

python 复制代码
import unittest
import sys

#定义测试用的函数
def add(v1,v2):
    return v1+v2

def subtract(v1,v2):
    return v1-v2

#复用前期定义的Car类
class Car(object):
    __slots__ = ('_color', '_number')

    @property
    def color(self):
        return self._color
    
    @color.setter
    def color(self,value):
        self._color = value

    @property
    def number(self):
        return self._number
    
    @number.setter
    def number(self,value):
        self._number = value
    
    @number.deleter
    def number(self):
        print('oops! number is deleted!')
    
    def func(self):
        print('car number: %d' %  self._number)
    pass

class TestAll(unittest.TestCase):
    def setUp(self):
        # 准备工作
        print("准备工作完成")
    
    def tearDown(self):
        # 结束后的工作
        print("结束清理工作完成")

    @unittest.skip("啊!我被永久的跳过了")
    def test_add(self):
        #测试用例实现对函数的调用
        self.assertEqual(add(1, 1), 2)

    # windows系统下,执行此测试用例。还可以使用版本号版本等等
    @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
    def test_subtract(self):
        #测试用例实现对函数的调用
        self.assertEqual(subtract(2, 3), -1)

    def test_car_color(self):
        car = Car()
        car.color ="blue"
        self.assertEqual(car.color, "blue")


    #属性测试
    def test_car_property(self):
        car = Car()
        with self.assertRaises(AttributeError):
            value = car.engine
  

if __name__ == '__main__':
    # 创建测试套件
    suite = unittest.TestSuite()
    suite.addTest(TestAll('test_add'))
    suite.addTest(TestAll('test_subtract'))
    suite.addTest(TestAll('test_car_property'))

    # 创建测试运行器
    runner = unittest.TextTestRunner()
    runner.run(suite)

结果输出:

python 复制代码
准备工作完成
结束清理工作完成
.准备工作完成
结束清理工作完成
.
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK (skipped=1)

模拟对象

Python的unittest.mock模块提供了一种创建模拟对象的方法,我们可以用它来模拟外部的、不可控的因素。

python 复制代码
import unittest
import sys
import datetime
#使用mock需要执行此引用
from unittest.mock import patch

#定义测试用的函数
def add(v1,v2):
    return v1+v2

def subtract(v1,v2):
    return v1-v2

#复用前期定义的Car类
class Car(object):
    __slots__ = ('_color', '_number')

    @property
    def color(self):
        return self._color
    
    @color.setter
    def color(self,value):
        self._color = value

    @property
    def number(self):
        return self._number
    
    @number.setter
    def number(self,value):
        self._number = value
    
    @number.deleter
    def number(self):
        print('oops! number is deleted!')
    
    def func(self):
        print('car number: %d' %  self._number)
    
    def say(self):
        current_hour = datetime.datetime.now().hour
        if current_hour < 12:
            return "Good morning!"
        elif current_hour < 18:
            return "Good afternoon!"
        else:
            return "Good evening!"
    pass

class TestAll(unittest.TestCase):
    def setUp(self):
        # 准备工作
        print("准备工作完成")
    
    def tearDown(self):
        # 结束后的工作
        print("结束清理工作完成")

    @unittest.skip("啊!我被永久的跳过了")
    def test_add(self):
        #测试用例实现对函数的调用
        self.assertEqual(add(1, 1), 2)

    # windows系统下,执行此测试用例。还可以使用版本号版本等等
    @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
    def test_subtract(self):
        #测试用例实现对函数的调用
        self.assertEqual(subtract(2, 3), -1)

    def test_car_color(self):
        car = Car()
        car.color ="blue"
        self.assertEqual(car.color, "blue")

    #属性测试
    def test_car_property(self):
        car = Car()
        with self.assertRaises(AttributeError):
            value = car.engine
    
    @patch('datetime.datetime')
    # 注意此处多了一个mock_datetime参数
    def test_car_say(self, mock_datetime):
        car = Car()
        mock_datetime.now.return_value.hour = 9
        self.assertEqual(car.say(), "Good morning!")

        mock_datetime.now.return_value.hour = 15
        self.assertEqual(car.say(), "Good afternoon!")

        mock_datetime.now.return_value.hour = 20
        self.assertEqual(car.say(), "Good evening!")
  

if __name__ == '__main__':
    # 创建测试套件
    suite = unittest.TestSuite()
    suite.addTest(TestAll('test_add'))
    suite.addTest(TestAll('test_subtract'))
    suite.addTest(TestAll('test_car_property'))
    suite.addTest(TestAll('test_car_say'))

    # 创建测试运行器
    runner = unittest.TextTestRunner()
    runner.run(suite)

结果输出:

python 复制代码
备工作完成
结束清理工作完成
.准备工作完成
结束清理工作完成
.准备工作完成
结束清理工作完成
.
----------------------------------------------------------------------
Ran 4 tests in 0.002s

OK (skipped=1)
相关推荐
Allen_LVyingbo8 分钟前
医疗AI基础2026-构建可靠智能体的编程路径(上)
大数据·数据库·人工智能·python·自动化
WWJA王文举36 分钟前
FreeRTOS事件组和任务通知详解:为什么任务通知比队列更轻量?
开发语言·php
Rnan-prince43 分钟前
堆与TopK · 从零到通透 —— 9 节全系列复盘
python·算法
wuyk5552 小时前
12.归并排序:分治思想的稳定排序算法
开发语言·数据结构·算法·排序算法
吴声子夜歌2 小时前
ApacheCommons——commons-text(模板替换与文本算法)
java·开发语言·算法·apache
2601_962294612 小时前
Python接口自动化测试实战:使用requests库
python·接口自动化测试·异常处理·requests库·api测试
砚底藏山河2 小时前
【量化纯GET实战 #23】多股票相关性:用收益率看板块联动
java·数据库·python·金融·数据分析
阿童木写作2 小时前
跨境电商翻译工具推荐:批量图片翻译+视频字幕实时翻译
人工智能·python·音视频
晶捷软件2 小时前
晶捷智能:集团型制造企业ERP如何实现多工厂统一管控
大数据·人工智能·python·制造
oyguyteggytrrwwwrt2 小时前
闵可夫斯基差演示
python