智一面的面试题提供python的测试题
使用地址:http://www.gtalent.cn/exam/interview?token=99ef9b1b81c34b4e0514325e9bd3be54

一、TestFixure:测试夹具
test fixture 表示为了开展一项或多项测试所需要进行的准备工作,以及所有相关的清理操作。

举个例子,在测试之前我们可能需要包含创建临时或代理的数据库、目录,或者启动一个服务器进程等操作,这些都可以依赖fixture来实现。

1.1 setUp() 与 tearDown() 方法
我们可能同时存在多个前置操作相同的测试。

我们可以把测试的前置操作从测试代码中拆解出来,并实现测试前置方法 setUp() 。在运行测试时,测试框架会自动地为每个单独测试调用前置方法。

在测试运行时,若 setUp() 方法引发异常,测试框架会认为测试发生了错误,因此测试方法不会被运行。

同理 tearDown() 方法在测试方法运行后进行清理工作。

若 setUp() 成功运行,无论测试方法是否成功,都会运行 tearDown() 。

参考示例:

import unittest

class StudyTestCase(unittest.TestCase):
    def setUp(self):
        print("setUp : 准备完成,可以测试...")

    def tearDown(self):
        print("tearDown : 测试完成 ...")

    def test_case1(self):
        print("run : test_case1")

    def test_case2(self):
        print("run : test_case2")



测试结果:

在这里插入图片描述
1.2 setUpClass() 与 tearDownClass() 方法
setUpClass()
在运行单个类中的测试之前调用的类方法。 使用类作为唯一参数调用setUpClass,并且必须将其装饰为classmethod()

@classmethod
def setUpClass(cls):
    ...



tearDownClass()
在单个类中的测试运行后调用的类方法。 使用类作为唯一参数调用tearDownClass,并且必须将其装饰为classmethod()

@classmethod
def tearDownClass(cls):
    ...



setUpClass and tearDownClass 示例
这些必须作为类方法实现。
如果要在基类上调用setUpClass和tearDownClass,则必须自己调用它们。 TestCase中的实现为空。

import unittest

class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._connection = createExpensiveConnectionObject()

    @classmethod
    def tearDownClass(cls):
        cls._connection.destroy()


如果在setUpClass期间引发异常,则不会运行该类中的测试,也不会运行tearDownClass。 跳过的类将不会运行setUpClass或tearDownClass。 如果该异常是SkipTest异常,则该类将被报告为已跳过而不是错误。

类和模块级别的固定装置在TestSuite中实现。 当测试套件遇到来自新类的测试时,将调用前一类(如果有)的tearDownClass(),然后调用新类中的setUpClass()。

1.3 setUpModule() 与 tearDownModule () 方法
同样,如果测试来自与先前测试不同的模块,则运行来自先前模块的tearDownModule,然后运行来自新模块的setUpModule。

我们需要注意以下几点:

在运行所有测试之后,运行最后的tearDownClass和tearDownModule。

共享fixture不能很好地发挥[潜在的]特性,如测试并行化,它们会破坏测试隔离。使用时要小心。

unittest测试加载程序创建的测试的默认顺序是将来自相同模块和类的所有测试组合在一起 。 这将导致每个类和模块仅一次调用setUpClass / setUpModule(等)。 如果我们将顺序随机化,以使来自不同模块和类的测试彼此相邻,则可以在一次测试运行中多次调用这些共享的夹具功能。

共享fixture不适合使用非标准排序的套件。对于不希望支持共享fixture的框架,仍然存在一个BaseTestSuite。

如果在共享夹具功能之一期间引发了任何异常,则将测试报告为错误。 因为没有相应的测试实例,所以创建了_ErrorHolder对象(与TestCase具有相同的接口)来表示错误。 如果您只是使用标准的单元测试测试运行程序,那么此细节并不重要,但是如果您是框架作者,则可能很重要。

1.3.1 setUpModule and tearDownModule 示例(单个模块中)
执行顺序为 :setUpModule 、setUpClass 、setUp TestCase(TestSuite) ,即按照模块、类、测试单元的setUp 。下来是 tearDown、tearDownClass、tearDownModule ,即按照与setUp相反的顺序来的。

import unittest

# 模块级夹具定义在模块中(测试类之外)
def setUpModule():
    print("模块级夹具 setUpModule : study_testfixture2.py")

def tearDownModule():
    print("模块级夹具 tearDownModule : study_testfixture2.py")

class Test(unittest.TestCase):
    @classmethod    # 装饰器,类成员方法
    def setUpClass(cls):
        print("类夹具 setUpClass ...")

    @classmethod
    def tearDownClass(cls):
        print("类夹具 tearDownClass ...")

    def test_case(self):
        print("run : Test_case")

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



测试结果:在这里插入图片描述
1.3.2 setUpModule and tearDownModule 示例(多个模块中)

# study_testfixture.py 模块
import os
import unittest

def setUpModule():
    print("模块级夹具 setUpModule : study_testfixture.py")

def tearDownModule():
    print("模块级夹具 tearDownModule : study_testfixture.py")

class StudyTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("类夹具 setUpClass : study_testfixture.py")
    @classmethod
    def tearDownClass(self):
        print("类夹具 tearDownClass : study_testfixture.py")

    def setUp(self):
        print("setUp ... study_testfixture.py")

    def tearDown(self):
        print("tearDown ... study_testfixture.py")


    def test_case1(self):
        print("run : test_case1 : study_testfixture.py")

    def test_case2(self):
        print("run : test_case2 : study_testfixture.py")

if __name__ == '__main__':
    suite = unittest.TestSuite()
    testcases = unittest.defaultTestLoader.discover(
        start_dir=os.getcwd(),  # 目录:os.getcwd()当前目录路径
        pattern='*.py'          # 文件: 所有以 .py 结尾的文件中 test开头的测试单元
    )
    suite.addTests( testcases)    # 加载测试用例集
    unittest.main(defaultTest='suite')

 

# study_testfixture2.py 模块
import unittest

def setUpModule():
    print("模块级夹具 setUpModule : study_testfixture2.py")

def tearDownModule():
    print("模块级夹具 tearDownModule : study_testfixture2.py")

class Test(unittest.TestCase):
    @classmethod    # 装饰器,类成员方法
    def setUpClass(cls):
        print("类夹具 setUpClass : study_testfixture2.py")

    @classmethod
    def tearDownClass(cls):
        print("类夹具 tearDownClass : study_testfixture2.py")

    def test_case(self):
        print("run : Test_case : study_testfixture2.py")

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



测试结果:在这里插入图片描述


如果setUpModule中引发了异常,则模块中的任何测试都不会运行,而tearDownModule也不会运行。 如果该异常是SkipTest异常,则该模块将被报告为已跳过而不是错误。

要添加即使在发生异常情况下也必须运行的清理代码,请使用addModuleCleanup。

unittest.addModuleCleanup(function, /, *args, **kwargs)
在tearDownModule()之后添加一个要调用的函数,以清理测试类中使用的资源。 将以与添加功能相反的顺序调用这些功能(LIFO)。 添加它们时,将使用传递到addModuleCleanup()中的任何参数和关键字参数来调用它们。

如果setUpModule()失败,这意味着未调用tearDownModule(),则仍将调用添加的任何清理函数。

unittest.doModuleCleanups()
如果在tearDownModule()之后或在setUpModule()如果setUpModule()引发异常的情况下无条件调用此函数。

它负责调用addCleanupModule()添加的所有清除函数。 如果需要在tearDownModule()之前调用清除函数,则可以自己调用doModuleCleanups()。

doModuleCleanups()一次将方法从清理函数的堆栈中弹出,因此可以随时调用它。

1.4 封装测试夹具
如上 1.3.2 示例中,如果每个测试单元所需要的setUp等操作都是相同的,每个 py模块中都需要写入了 setUp、tearDown 等相关的函数,让代码显得很繁琐,不变于阅读和理解。那么我们可以选择将测试夹具进行封装,成为一个新的模块。

文件结构:在这里插入图片描述

说明:在myunite中,设计MyUnite类继承unittest.TestCase类,然后实现 setUp 等方法。 在 study_testfixture.py 等模块中,只需要继承 Myunite 类即可。

runall模块:一次加载所有模块中的测试集,进行测试。

# myunite.py
import unittest


class MyUnite(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("类夹具 setUpClass : study_testfixture.py")
    @classmethod
    def tearDownClass(self):
        print("类夹具 tearDownClass : study_testfixture.py")

    def setUp(self):
        print("setUp ... study_testfixture.py")    def tearDown(self):
        print("tearDown ... study_testfixture.py")


 

# study_testfixture.py

# 封装的unittest的setUp等操作
from 测试.fixture.myunite import MyUnite

class StudyTestCase(MyUnite):

    def test_case1(self):
        print("run : test_case1 : study_testfixture.py")

    def test_case2(self):
        print("run : test_case2 : study_testfixture.py")1
# study_testfixture2.py
from 测试.fixture.myunite import MyUnite


class Test(MyUnite):
    @classmethod    # 装饰器,类成员方法
    def setUpClass(cls):
        print("类夹具 setUpClass : study_testfixture2.py")

    @classmethod
    def tearDownClass(cls):
        print("类夹具 tearDownClass : study_testfixture2.py")

    def test_case(self):
        print("run : Test_case : study_testfixture2.py")

 

# runall.py
import os
import unittest

if __name__ == '__main__':
    suite = unittest.TestSuite()
    testcases = unittest.defaultTestLoader.discover(
        start_dir=os.getcwd(),  # 目录:os.getcwd()当前目录路径
        pattern='*.py'  # 文件: 所有以 .py 结尾的文件中 test开头的测试单元
    )
    suite.addTests(testcases)  # 加载测试用例集
    unittest.main(defaultTest='suite')


————————————————