【问题标题】:How to augment a class from an external library with own methods?如何使用自己的方法从外部库中扩充类?
【发布时间】:2011-11-11 13:20:34
【问题描述】:

我有一些特殊情况需要在 django 中进行测试。我正在尝试通过编写自己的测试用例来扩展现有的 django 测试。这是我目前的做法。

from django.tests import TestCase

# define my own method as a function
def assertOptionsEqual(self, first, second):
    # logic here
    pass

# Attach the method to the TestCase class. This feels inelegant!
TestCase.assertOptionsEqual = assertOptionsEqual

# tests go here
class KnownGoodInputs(TestCase):
    def test_good_options(self):
        self.assertOptionsEqual(...)

虽然这可行,但将方法定义为以self 作为第一个参数的函数,然后将其附加到TestCase 感觉不优雅。有没有更好的方法来用我自己的方法扩充 TestCase 类?我可以做到这一点...

class MyTestCase(TestCase):
    def assertOptionsEqual(self, first, second):
        ...

并使用MyTestCase 进行所有测试,但想知道是否有更好的选择。谢谢!

【问题讨论】:

  • 子类化并使用另一个方法名怎么样?

标签: python class inheritance methods monkeypatching


【解决方案1】:

我认为您已经涵盖了这两种选择。您可以子类或monkeypatch。通常,monkeypatching,实际上在运行时更改 3rd 方类是不受欢迎的,但取决于您需要进行哪些更改,它可能是解决错误或确保每次使用该类时都有您的新方法的唯一方法.

因为使用你的方法的唯一测试将是你的 测试,monkeypatching 是不必要的,继承TestCase 是非常合理的。通常,当您需要扩充现有类的方法时,您会使用猴子补丁。例如,如果您希望在现有测试用例中对TestCase.assertEqual 的调用增加逻辑以与Option 对象进行比较,您可以通过以下方式对TestCase.assertEqual 进行monkeypatch 以包含您的自定义逻辑及其正常逻辑:

originalAssertEqual = TestCase.assertEqual
def newAssertEqual(self, first, second):
    result = originalAssertEqual(first, second)
    if isinstance(first, Option) and isinstance(second, Option):
        # do your custom comparison
    return result
TestCase.assertEqual = newAssertEqual 

然而,似乎至少在这个例子中,子类和猴子补丁都是不必要的。

假设问题是调用self.assertEqual(firstOptions, secondOptions) 失败,即使Option 实例相等,您不需要编写新的assertOptionsEqual 方法。您可能只需要您的 Option 对象来正确定义 __eq__

所以假设你有:

class KnownGoodInputs(TestCase):
    def test_good_options(self):
        first, second = systemUnderTestGetOptions(...)
        self.assertOptionsEqual(first, second)

上面firstsecond的类是什么?

对于所有 Python 内置类型,assertEqual 应该可以工作。对于自定义 Option 类,只需执行以下操作:

类选项(对象): def 初始化(自我): use_foo = False use_bar = True

def __eq__(self, other):
    if (self.use_foo == other.use_foo and
        self.use_bar == other.use_bar):
        return True
    return False

然后假设 firstsecondOption 的实例,您可以编写测试:

class KnownGoodInputs(TestCase):
    def test_good_options(self):
        first, second = systemUnderTestGetOptions(...)
        self.assertEqual(first, second)

【讨论】:

  • 感谢您的详细解答!尝试定义__eq__ 是首选。然而,被比较的对象是没有定义__eq__ 的 Django 原生对象(聚合、查询集等)。所以我要么必须为一些原生 Django 对象修改 __eq__ 方法,要么修改 TestCases。所以我想我是在试图选择两个邪恶中较小的一个! ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 2017-07-27
  • 1970-01-01
相关资源
最近更新 更多