2

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

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

有没有办法做到这一点?

蟒蛇 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() 方法中进行清理会导致:

设置

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

相反,我想要这个:(
如果在所有测试完成后执行 tearDownX() 方法是可能的)

设置

(测试1)
清理
测试
。. .
(测试 N)
清除
测试

tearDownX(自我)
清理(最终)

这或多或少是我在过去几年中完成测试设计的方式。它试图对中断的调试会话(无清理)和脏的初始数据库状态进行防弹。


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

我希望这一切都是有道理的。

谢谢,

亚历山德罗

4

1 回答 1

2

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

文档

setUp() 调用方法来准备测试夹具。这是在调用测试方法之前立即调用的;除了AssertionError or SkipTest,此方法引发的任何异常都将被视为错误而不是测试失败。默认实现什么也不做。

tearDown() 在调用测试方法并记录结果后立即调用的方法。即使测试方法引发异常也会调用此方法,因此子类中的实现可能需要特别小心检查内部状态。此方法引发的除AssertionErroror之外的任何异常SkipTest都将被视为附加错误而不是测试失败(从而增加报告的错误总数)。仅当成功时才会调用此方法setUp(),而不管测试方法的结果如何。默认实现什么也不做。

更新(评论后)

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

无论如何,由于您不应该指望测试执行顺序,也不应该让您的测试相互依赖,因此使用该方法为每个测试创建 db 固定装置并在每次测试后使用setUp方法清理它仍然是明智的tearDown

另一种选择是在测试中为数据库使用模拟,因此您无需担心清理它。

于 2017-04-18T23:14:40.227 回答