【问题标题】:Python unittest tearDownClass() for the instance, how to have it?实例的Python unittest tearDownClass() ,如何拥有它?
【发布时间】:2017-04-18 23:11:00
【问题描述】:

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

我的目的是在所有测试用例运行后清理数据库。
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() 方法中进行清理会导致:

设置

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

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

设置

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

tearDownX(自我)
清理(​​最终)

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


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

我希望这一切都有意义。

谢谢,

亚历山德罗

【问题讨论】:

  • 这个用例不会得到很好的支持,因为它被视为一种反模式。您可以编写自己的测试运行程序来执行此操作,但 IMO 您正在自找麻烦。是否有任何原因您不能为每个测试设置和拆卸?
  • 我不想在每次测试结束时调用清理,因为根据我的真实世界经验,我必须在每次测试之前(也)清理数据库。因此,在每个测试结果之后进行清理(也),在测试 X 和测试 Y 之间双重调用“清理”(如果我有 10 个测试,它被称为“100% 不必要”的 9 次)。解释说我在每个测试(执行之前)都调用 clenup 仍然使它成为反模式?如果是,您能否解释或链接一些东西,我想更好地了解这一点?谢谢
  • 我从来没有遇到过使用 SQLAlchemy 固定装置进行清理的问题。 sqlalchemy-fixtures.readthedocs.io/en/latest

标签: python python-unittest teardown


【解决方案1】:

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

来自docs

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

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

更新(在 cmets 之后)

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

无论如何,由于您不应该指望测试执行顺序,也不应该让您的测试相互依赖,因此使用 setUp 方法为每个测试创建 db 夹具并使用 @ 清理它仍然是明智之举每次测试后987654334@方法。

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

【讨论】:

  • 在所有测试完成后,我需要一个 tearDown 类,而不是每一个。正如我在 OP 中所说的, tearDown()every 测试结束时执行,我不想使用它。
  • 操作,抱歉,我误读了您的问题。看起来您需要以不同的方式设计代码。 tearDownClass方法中怎么不能实例化数据库清理对象
  • 我可以“思考”一些东西。我可以在 tearDownClass() 中复制我想要使用的函数中的所有代码,但是......为什么我必须污染我的代码来完成一个如此(在我看来)常见的任务?为什么(在哪里/如何)隐藏此功能?在任何情况下,如果我必须访问在实例中创建的某些内容(唯一 ID),我如何以简单明了的方式访问类方法(tearDownClass)中的这些信息?
  • 使其成为类方法
  • 几乎每条记录的开头都有一个 self._cleanup_record() 。因为在现实世界中,当你执行测试时,你不能依赖数据库是干净的这一事实(我不想更多地解释这一点,但以防万一)。此函数使用在每次 setUp() 调用时初始化的 self.repository。显然,如果我创建(也)一个新的 self._cleanup_record_class(cls) 我不能使用 self.repository 属性。在任何情况下,它都会导致有两种方法可以完成相同的工作。这不是正确的解决方案(不适用于我的情况)。
猜你喜欢
  • 2018-11-14
  • 1970-01-01
  • 2014-01-09
  • 1970-01-01
  • 2011-08-09
  • 2013-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多