Python unitit tearDownClass()为实例,如何拥有它?

时间:2017-04-18 23:11:01

标签: python python-unittest teardown

我需要实例的 tearDownClass(cls)方法。 我的意思是我可以参考自我实例),而不是 cls )。
一种tearDownTestCase(自我)。

我的目的是在所有测试用例运行后清理数据库 tearDown(self)在每次测试结束时执行,我不想使用它。
tearDownClass(cls)在所有测试完成后执行一次,但它不包含对self的引用,我需要访问 self 的属性(更确切地说,一个功能)。

有办法实现这个目标吗?

Python 3.6

真实场景示例:

import unittest

'''
The real records saved in the database came from an external source (an API) so the ID is preassigned.
For the test I use everywhere a predefined fixed id, so the code result more clean.
'''

record_id = "TEST"

class RepositoryTest(unittest.TestCase):


    def setUp(self):
        # real initialization, reading connection string from config, database name, collection...
        self.repository = None
        # self._cleanup_record() # maybe here is executed too many unnecessary times

    def tearDown(self):
        # here is executed unnecessarily, because (where needed) the cleanup is eventually executed BEFORE the test (or in its beginning)
        self._cleanup_record()

    ### pseudo (desired) method ###
    def tearDownTestCase(self):
        self._cleanup_record()  

    def tearDownClass(cls):
        # self._cleanup_record()  # self is not available
        # rewrite the same code of initialization and _cleanup_record()
        # I want to a void (or simplify this)
        pass

    # this is 1 of N tests
    def test_save_record(self):

        # cleanup (because I don't know in which state the database is)
        self._cleanup_record()  # almost every test require this, so it can be done in setUp()

        # arrange
        record = self._create_record()

        # act
        self.repository.save_record(record)

        # assert
        saved_record = self._get_record()
        self.assertEquals(saved_record["my field"], record["my field"])



    # utility methods

    def _get_record(self):
        # use self.repository and return the record with id = record_id
        pass # return the record

    def _create_record(self):
        # use self.repository and create (and save) a record with id = record_id
        return None # return the saved record

    def _cleanup_record(self):
        # use self.repository and delete the record with id = record_id (if exists)
        pass

在tearDown()方法中进行清理,结果是:

setUp

.test 1
清理
测试
清理(​​=冗余)
。 。 。
.test N
清理
测试
清理

相反,我想要这个:
(并且可以在所有测试完成后执行tearDownX()方法)

setUp

(测试1)
cleaup
测试
。 。 。
(测试N)
cleaup
测试

tearDownX(self)
清理(​​最后)

这或多或少是我在过去几年的测试设计中结束的。 它试图防止中断的调试会话(没有清理)和脏的初始数据库状态。

作为临时解决方案,我在tearDownClass(cls)方法中复制了清理方法,但我并不高兴。理想情况下,我可以简单地调用self._cleanup_record,但这是不可能的,因为tearDownClass是一个类方法。

我希望所有这些都有意义。

谢谢,

的Alessandro

1 个答案:

答案 0 :(得分:1)

是的,setUp下有一对实例方法tearDownunittest.TestCase,分别在每次测试之前和之后执行。

来自docs

  

setUp()   调用准备测试夹具的方法。这就是所谓的   在调用测试方法之前; AssertionError以外的人   或SkipTest,此方法引发的任何异常都将被视为   错误而不是测试失败。默认实现   什么都没有。

     

tearDown()   测试方法完成后立即调用的方法   调用并记录结果。即使是测试方法,也会调用此方法   引发了异常,因此子类中的实现可能需要   检查内部状态要特别小心。任何例外,   除AssertionErrorSkipTest之外,此方法引发的将是   被认为是一个额外的错误而不是测试失败(因此   增加报告的错误总数)。这种方法只会   如果setUp()成功,则被调用,无论结果如何   测试方法。默认实现不执行任何操作。

更新(评论后)

嗯,您可能别无选择,只能重新设计代码。您可以将 db cleanup方法设为类方法而不是实例方法。

无论如何,既然你不应该指望测试执行顺序,也不要让你的测试相互依赖,那么使用setUp方法为每个测试创建数据库夹具仍然是明智的。每次测试后用tearDown方法清除它。

另一个选择是在测试中使用mock作为数据库,因此您不必担心要清理它。