如何使用自己的方法从外部库扩充类?

时间:2011-09-06 18:03:21

标签: python class inheritance methods monkeypatching

我有一些需要在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进行所有测试,但想知道是否有更好的选择。谢谢!

1 个答案:

答案 0 :(得分:1)

我认为你已经涵盖了两种选择。你可以子类或monkeypatch。通常,monkeypatching,实际上在运行时改变第三方类是不受欢迎的,但取决于你需要做什么改变它可能是解决bug的唯一方法或确保每次使用该类时它都有你的新方法

由于使用您的方法的唯一测试将是您的测试monkeypatching是不必要的,并且子类TestCase是非常合理的。通常,当您需要扩充现有类的方法时,您将使用monkeypatching。例如,如果您希望在现有测试用例中调用TestCase.assertEqual,并使用逻辑来与Option对象进行比较,则可以将monkeypatch TestCase.assertEqual包含在您的自定义逻辑加上其正常逻辑中做类似的事情:

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 

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

假设问题是即使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类,只需执行以下操作:

class Option(object):     def init (个体经营):         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)