单元测试对开发任何项目都是一个好习惯,在Python开发中我们经常使用标准库中的unittest及第三方的单元测试框架pytest完成单元测试工作。这里记录一下,如何在一次单元测试中持久化地保留一个实例化对象(例如深度学习模型这类加载比较耗时的对象)以供多个testcase使用。
Logo

unittest

傻子都知道的方法:在一个testcase函数中完成多个测试

import unittest
class A:
    def __init__(self):
        self.foo = True
        self.bar = True


class MyTestCaseA(unittest.TestCase):
    def test_something(self):
        a = A()

        def test_foo():
            self.assertTrue(a.foo)

        def test_bar():
            self.assertTrue(a.bar)

        test_foo()
        test_bar()

实不相瞒,在之前我的确是这样完成对实例的单元测试的...惭愧惭愧...

面对对象思想:使用Testcase共用的静态变量

class MyTestCaseB(unittest.TestCase):
    a = A()
    b = 'foo'

    def test_something_a(self):
        self.assertTrue(MyTestCaseB.a.foo)
        self.assertTrue(MyTestCaseB.a.bar)
        # 在只读情况下可以使用self访问
        # self.assertTrue(self.a.foo)
        # self.assertTrue(self.a.bar)
        # 在测试过程中通过self对不可变对象的修改只在当前test函数中生效
        self.b = 'bar'
        self.assertEqual(self.b, 'bar')
        # 如果希望对不可变对象的修改持续保留,可以通过MyTestCaseB.b或self.__class__.b进行修改
        # Source: https://stackoverflow.com/questions/21447740/persist-variable-changes-between-tests-in-unittest
        # 使用self.__class__.b更加精确,并支持后续TestCase的继承
        # ------------------------------------------------------------------------
        # 在测试过程中对self可变对象的修改会持续保留(得益于静态变量共享)
        self.a.foo = False
        self.assertFalse(self.a.foo)

    def test_something_b(self):
        self.assertFalse(self.a.foo)  # 这一行会通过,因为保留了上一个测试中对self.a的改变
        self.assertEqual(self.b, 'bar')  # 这一行不会通过,因为上一个测试中对self.b的改变不会保留

在这里需要注意一下在非只读情形下对不可变对象的修改不会在其他test函数中得以保留,同时注意默认情况下test函数执行的顺序按照函数名字典序升序排列。

pytest

pytest通过默认名为conftest.py的文件可以设定返回一些持久化的实例:

# 文件名:conftest.py
import pytest

class A:
    def __init__(self):
        self.foo = True
        self.bar = True

@pytest.fixture(scope='module')
def instance_test():
    return A()
# 文件名:test_A.py
import pytest

def test_A(instance_test): # 注意:测试函数名与conftest.py中返回实例对象的函数名保持一致
    assert instance_test.foo
    
if __name__ == '__main__':
    pytest.main()
Last modification:January 26th, 2021 at 02:57 pm
If you think my article is useful to you, please feel free to appreciate