【问题标题】:Run tests for a BaseClass for all DerivedClass为所有派生类运行基类测试
【发布时间】:2023-03-15 05:15:01
【问题描述】:

给定具有一些多重继承和/或混合(无论您如何称呼它)的类的小层次结构。

我对每个单独的基类和 mixin 都有一个详细的测试用例 (unittest.TestCase)。

如何为从基类和 mixin 派生的类重用这些测试用例?我觉得,测试/断言派生类继承自某些基类并不足以确保它继承基类的特定行为。

我想写一些类似的东西:

class Base(object):
  # provides certain behavior

class Derived(Base, Mixin):
  # does some additional stuff compared to Base and Mixin

class BaseTest(unittest.TestCase):
  # tests on Base's behavior

class DerivedTest(unittest.TestCase):
  def setUp(self):
    self.default = Derived()

  def test_has_behavior_of_base(self):
    # instead of
    self.assertIsInstance(self.default, Base)
    self.assertIsInstance(self.default, Mixin)
    # write
    self.assertPasses(BaseTest, Derived)

有没有一种 pythonic 方法可以通过 Pythons unittest 模块和nose 包的帮助来实现这一点?

【问题讨论】:

    标签: python-3.x nose python-unittest


    【解决方案1】:

    一般来说,由于 Python 是一种 duck-typed 语言,因此最好尽量减少对显式类型/类的检查(至少如果您要更多Pythonic 方法)。

    因为 duck-typing 主要依赖于行为,并且 nose 如果您使用目录调用它并相应地命名您的测试类和方法(即包含单词 test 等),我会推荐以下内容:

    为您的基类类定义一个测试类,测试基类的所有行为。将公共代码分解为非测试方法,例如baseClassCore,它调用实际方法,获取结果,然后返回它们。然后为每个 派生 类设置一个测试,该测试调用baseClassCore 代码并断言预期结果(如果断言代码对所有这些类也是通用的,也可以将其分解然后调用来自测试方法)。

    然后,对于特定的派生类,为每个仅测试这些类独有的行为的类创建一个测试类。

    您也可以在 派生 类测试而不是 base 类测试中针对特定类型的测试调用 baseClassCore —— 这是一个问题偏好。

    一旦这些都被定义(其中许多将只是核心代码的包装器,因此它们在 JUnit 结果中被拆分为单独的测试并传递所需的特定类型),运行nose 针对整个目录应该检测并运行它们。如果您使用 -v 标志运行,您将在运行时获得方法名称,或者,如果存在,则获得方法签名下方的文档字符串,而不仅仅是状态字母。

    请注意,您不需要显式使用 unittest。如果您从 unittest.TestCase 派生测试类,那么 nose 就足以获得与 JUnit 兼容的行为。

    顺便说一句,如果您有任何需要的配置(截止日期、要使用的服务器等)nose-testconfig 非常方便 (https://pypi.python.org/pypi/nose-testconfig)。我通常将它与 JSON 文件一起使用,然后将其输入到名为 configdict

    【讨论】:

      【解决方案2】:

      这是一个运行的填充示例。正方形派生自矩形。如果我们从TestRectangle派生TestSquare,其中TestRectangle是从unittest.TestCase派生的,那么TestRectangle中的所有测试方法也会从TestSquare运行。

      import unittest
      
      
      class Rectangle(object):
      
          def __init__(self, width, height):
              self._width = width
              self._height = height
      
          def get_area(self):
              return self.get_width() * self.get_height()
      
          def get_width(self):
              return self._width
      
          def get_height(self):
              return self._height
      
          def set_width(self, width):
              self._width = width
      
          def set_height(self, height):
              self._height = height
      
      
      class Square(Rectangle):
      
          def __init__(self, side):
              self._side = side
      
          def get_width(self):
              return self._side
      
          def set_width(self, width):
              self._side = width
      
          def get_height(self):
              return self._side
      
          def set_height(self, height):
              self._side = height
      
      
      class TestRectangle(unittest.TestCase):
      
          def setUp(self):
              self.default = Rectangle(2, 3)
      
          def test_area(self):
              self.assertEqual(
                  self.default.get_area(),
                  self.default.get_width() * self.default.get_height())
      
          def test_set_get(self):
              self.default.set_width(4)
              self.default.set_height(5)
              self.assertEqual(self.default.get_width(), 4)
              self.assertEqual(self.default.get_height(), 5)
      
      class TestSquare(TestRectangle):
      
          def setUp(self):
              self.default = Square(3)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-29
        • 2011-11-09
        • 1970-01-01
        • 1970-01-01
        • 2017-01-08
        • 2013-11-17
        • 2013-04-27
        相关资源
        最近更新 更多