【问题标题】:Is there any good reason to catch exceptions in unittest transactions?是否有充分的理由在单元测试事务中捕获异常?
【发布时间】:2019-04-23 19:41:52
【问题描述】:

unittest 模块非常适合检测代码中的问题。 我理解使用断言隔离和测试部分代码的想法:

self.assertEqual(web_page_view.func, web_page_url)

但除了这些断言之外,您之前可能还有一些逻辑,在相同的测试方法中,可能会出现问题。

我想知道在 TestCase 子类的方法中是否需要考虑手动异常处理。

因为如果我在 try-catch 中包装了一个块,如果失败了,测试返回 OK 并且不会失败:

    def test_simulate_requests(self):
        """
        Simulate requests to a url
        """
        try:
           response = self.client.get('/adress/of/page/')
           self.assertEqual(response.status_code, 200)
        except Exception as e:
            print("error: ", e)

在此类测试中是否应始终避免异常处理?

【问题讨论】:

  • 通常的做法是在您期望引发一些异常时使用assertRaises 断言。在其他情况下,您应该将它们视为常规测试,而不是自己手动捕获任何异常。

标签: python django unit-testing


【解决方案1】:

答案的第一部分:

正如您所说的,在实际测试之前需要一些逻辑。属于单元测试的代码可以分为四个部分(我在下面使用 Meszaros 的术语):设置、练习、验证、拆卸。通常,测试用例的代码是这样构造的,即四个部分的代码被清晰地分开并按照精确的顺序排列——这被称为四阶段测试模式。

练习阶段是测试的核心,在此执行应在测试中检查的功能。该设置确保这发生在明确定义的上下文中。因此,您在此术语中所描述的是在设置过程中出现故障的情况。这意味着,未满足有意义地执行要测试的功能所需的先决条件。

这是一种常见的情况,这意味着您实际上需要能够区分测试的三种结果:测试可以成功通过,可以失败,或者只是没有意义。

幸运的是,python 中有一个答案:您可以跳过测试,如果跳过测试,则会记录下来,但既不作为失败也不作为成功。跳过测试可能是处理示例中所示情况的更好方法。下面是一段小代码,演示了一种跳过测试的方法:

import unittest
class TestException(unittest.TestCase):
   def test_skipTest_shallSkip(self):
      self.skipTest("Skipped because skipping shall be demonstrated.")

答案的第二部分:

您的测试似乎有一些不确定的元素。 self.client.get 可以抛出异常(但只是有时——有时不会)。这意味着您无法控制测试执行期间的上下文。在单元测试中,您应该尽量避免这种情况。您的测试应该具有确定性的行为。

实现此目的的一种典型方法是将您的代码与导致不确定性的组件隔离开来,并在测试期间用模拟替换这些组件。模拟的行为完全由测试代码控制。因此,如果您的代码使用某些组件进行网络访问,您将模拟该组件。然后,在某些测试用例中,您可以指示 mock 模拟成功的网络通信以查看您的组件如何处理此问题,而在其他测试中,您可以指示 mock 模拟网络故障以查看您的组件如何应对这种情况。

【讨论】:

    【解决方案2】:

    测试有两种“坏”状态:失败(当其中一个断言失败时)和错误(当测试本身失败时 - 您的情况)。

    首先,不言而喻,最好以达到其断言的方式构建您的测试。

    如果你需要断言一些测试代码引发异常,你应该使用with self.assertRaises(ExpectedError)

    如果测试中的某些代码引发异常 - 最好从“错误”结果中了解它,而不是看到“确定所有测试都已通过”

    如果您的测试逻辑确实假设测试本身可能会失败并且这是正常行为 - 可能测试是错误的。可能您应该使用模拟 (https://docs.python.org/3/library/unittest.mock.html) 来模仿 api 调用或其他东西。

    在你的情况下,即使测试失败,你也会用 bare except 来捕捉它,然后说“好的,继续”。反正实现是错误的。

    最后:不,你的测试用例中不应该有例外

    附:最好使用 test_what_you_want_to_test_name 调用您的测试函数,在这种情况下,可能 test_successful_request 就可以了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 2020-10-02
      • 1970-01-01
      • 2021-07-29
      • 1970-01-01
      • 2015-10-10
      • 2014-09-22
      相关资源
      最近更新 更多