【问题标题】:How to run the same unittest suite with several backends如何使用多个后端运行相同的单元测试套件
【发布时间】:2012-10-16 15:44:41
【问题描述】:

我有一个 JSON 解析器库 (ijson) 和一个使用 unittest 的测试套件。该库实际上有几个解析实现——“后端”——以具有相同 API 的模块的形式。我想为每个可用的后端自动运行几次测试套件。我的目标是:

  • 我想将所有测试保存在一个地方,因为它们与后端无关。
  • 我希望当前使用的后端名称在测试失败时以某种方式可见。
  • 我希望能够像 unittest 通常允许的那样运行单个 TestCase 或单个测试。

那么为此组织测试套件的最佳方式是什么?编写自定义测试运行器?让 TestCases 自己加载后端?必须为每个后端生成单独的 TestCase 类?

顺便说一句,我并没有特别与 unittest 库结婚,如果它解决了问题,我愿意尝试另一个。但是 unittest 更可取,因为我已经有了测试代码。

【问题讨论】:

    标签: python unit-testing


    【解决方案1】:

    一种常见的方法是使用一个抽象方法将所有测试组合在一个类中,该方法创建一个后端实例(如果您需要在测试中创建多个实例),或者期望 setUp 创建一个后端。

    然后您可以根据需要创建创建不同后端的子类。

    如果您使用自动检测TestCase 子类的测试加载器,您可能需要进行一项更改:不要将公共基类设为TestCase 的子类:而是将其视为mixin,并使后端类成为 TestCase 和 mixin 的子类。

    例如:

    class BackendTests:
        def make_backend(self):
            raise NotImplementedError
    
        def test_one(self):
            backend = self.make_backend()
            # perform a test on the backend
    
    class FooBackendTests(unittest.TestCase, BackendTests):
        def make_backend(self):
            # Create an instance of the "foo" backend:
            return foo_backend
    
    class BarBackendTests(unittest.TestCase, BackendTests):
        def make_backend(self):
            # Create an instance of the "bar" backend:
            return bar_backend
    

    从上述构建测试套件时,您将拥有独立的测试用例 FooBackendTests.test_oneBarBackendTests.test_one,它们在两个后端测试相同的功能。

    【讨论】:

    • 但是实际上为每个后端运行多次测试对我没有帮助吗?如果我没有遗漏任何东西,我将不得不在每个测试方法中手动编写一个“for”循环来通过后端。
    • 哦,对不起,忽略这一点,我只是更仔细地重新阅读了您的答案。我试试,谢谢!
    • 不需要 for 循环,对。后端测试用例类继承它们自己的每个通用测试的副本。
    • 感谢代码示例。顺便说一句,更简单的方法是将后端作为类属性而不是从方法中返回。
    • 如果一个类属性对于您的用例来说已经足够了,那么就继续吧——最简单的可行的解决方案通常是最好的。我在示例中使用了一种方法,因为有时需要花费更多精力来设置后端进行测试(例如,他们可能需要访问临时目录或其他需要清理的资源)。
    【解决方案2】:

    我采用了 James Henstridge 的想法,使用一个包含所有测试的 mixin 类,但实际的测试用例随后会强制生成,因为后端在导入时可能会失败,在这种情况下我们不想测试它们:

    class BackendTests(object):
        def test_something(self):
            # using self.backend 
    
    # Generating real TestCase classes for each importable backend
    for name in ['backend1', 'backend2', 'backend3']:
        try:
            classname = '%sTest' % name.capitalize()
            locals()[classname] = type(
                classname,
                (unittest.TestCase, BackendTests),
                {'backend': import_module('backends.%s' % name)},
            )
        except ImportError:
            pass
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-19
      • 1970-01-01
      • 2016-11-07
      • 1970-01-01
      • 1970-01-01
      • 2014-11-23
      • 1970-01-01
      • 2014-10-02
      相关资源
      最近更新 更多