Python标准库中的模块unittest提供了代码测试工具。

unittest 核心组成

unittest 由以下核心组成部分。

1.Test Fixture

Test Fixture 通常用来做测试用例的准备或者清理工作。比如测试开始前的数据准备或者测试结束后的数据清理等。Python 通过 setUp()、tearDown()、setUpClass()、tearDownClass() 这 4 个钩子函数(Hook)来实现测试的准备和清理工作。

2.Test Case

Test Case 是 unittest 的最小单元,一个 Test Case 就是一个测试用例,通常 Test Case 会继承 TestCase 这个基类。

3.Test Suite

Test Suite 是测试套件,就是我们常说的测试用例集,它可以包含一个或多个测试用例。

4.Test Loader

Test Loader 用来从提供的类(classes)和模块(modules)中生成测试用例集,默认情况下unittest 会提供一个 default test loader。

5.Test Runner

Test Runner 是测试执行器,用来进行测试用例的执行和测试结果的输出。

unittest 运行原理

知道了 unittest 的 5 大核心类,我们看下 unittest 的运行原理,如图所示:

unittest框架和pytest框架搭建 unittest框架原理_Test

Test Cases 包括一个或者多个 TestCase 类,其中保存了具体的测试过程,你可以在测试类里使用 Test Fixture,例如setUp()、tearDown() 进行测试开始前的准备和结束后的清理工作。

TestSuite 包括一个或者多个 TestSuite 类,其中 TestSuite 包括了一个或多个 TestCase,也可以包括其他 TestSuite。TestSuite 通过 addTest() 或者 addTests() 方法把一个个的测试用例或者测试用例集(TestSuite)组装起来成为一个新的测试用例集。

TestLoader 类加载本地或从外部文件中定义好的 TestCase 或者 TestSuites。

TestRunner 包括TextTestRunner类, 它提供了运行测试的标准平台。测试运行可以通过 unittest.main() 或者 python -m unittest xxx.py 来运行。

Test Results Collector 包括 TestResults 类,它为测试结果提供了一个标准容器,它存储运行的测试用例状态,例如 errors、failures、skipped,测试的结果可以直接在 Console 输出,也可以为通过其他形式输出,例如 Text、result、output。

 

单元测试原理:包含对函数的测试和对类的测试。

1、通过使用unittest框架,对函数进行调用。

2、用断言来判断函数的输出是否与预期一致,如果一致,说明测试通过,如果不一致,则说明代码有问题,需要修改。 

单元测试中每一个测试用例是一个方法。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些清醒的测试。

测试函数

待测函数:

def get_formatted_name(first,last):
    """输出姓名"""
    full_name=first+' '+last
    return full_name.title()

测试类:

import unittest
from testcase.survery import get_formatted_name
class NameTestCase(unittest.TestCase):
    """测试函数的类"""
    def test_first_last_name(self):
        name=get_formatted_name('janis','jopin')
        self.assertEqual(name,'Janis Jopin')

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

 1、测试类的命名,最好让它看起来与要测试的函数相关,并包含字样Test,这个类必须继承unittest.TestCase

2、运行测试类时,所有test开头的方法都会自动运行。

3、断言 用来核实得到的结果是否与期望的结果一致。前面是调用输出,后面是预期输出。如果调用与预期一致,则测试通过。如果测试未通过,则意味着编写的代码有错误。

测试类 

很多程序中都会用到类,因此,证明类能够正确工作大有裨益。如果针对类的测试通过了,你就能确信对类所做的改进没有意外地破坏其原有的行为。

类的测试与函数的测试相似,所做大部分工作都是测试类中方法的行为。但存在不同之处。

待测类:

class Survery():
    """收集米明调查问卷的答案"""
    def __init__(self,question):
        self.question=question
        self.responses=[]
    def show_question(self):
        """显示调查问卷"""
        print(self.question)

    def store_response(self,new_response):
        """存储单份调查问卷"""
        self.responses.append(new_response)
    def show_result(self):
        """显示收集到的所有答卷"""
        print("Survey result:")
        for response in self.responses:
            print(response)

使用这个程序的代码:

from testcase.survery import Survery
question="what language did you first learn to speak?"
my_survery=Survery(question)
my_survery.show_question()
while True:
    response=input("language:")
    if response=='q':
        break
    my_survery.store_response(response)
my_survery.show_result()

 测试类:通过两个测试方法,来判断单个答案和三个答案能否被存储在responses中。

import unittest
from testcase.survery import Survery
class TestSurvery(unittest.TestCase):
    def setUp(self):
        question = "What language did you first learn to speak?"
        self.my_survery = Survery(question)
        self.responses = ['English', 'Spanish', 'Janpanese']
    """针对Survery类的测试"""
    def test_store_single_response(self):
        """测试单个答案会被妥善的存储"""
        self.my_survery.store_response(self.responses[0])
        self.assertIn(self.responses[0],self.my_survery.responses)
    def test_store_three_responses(self):
        """测试三个答案会被妥善地存储"""

        for response in self.responses:
          self.my_survery.store_response(response)
        for response in self.responses:
            self.assertIn(response,self.my_survery.responses)




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

1、变量名包含前缀self 即存储在属性中,因此可在这个类的任何地方使用。
2、setup()让测试方法编写起来更容易:可在setup()方法中创建一系列实例并设置它们的属性,
再在测试方法中直接使用这些实例。相比于在每个测试方法中都创建实例并设置其属性,要容易得多。

什么时候用单元测试?

1)新写代码时,运行单元测试,检查代码是否正确。

2)修改代码时,运行单元测试,检查代码是否修改正确。