如何为外部库的类添加自定义方法?
我在使用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 个回答
我觉得你已经提到了两种选择。你可以选择子类化或者猴子补丁。通常来说,猴子补丁就是在运行时直接修改第三方类,这种做法是不太被推荐的,但有时候为了修复一个bug或者确保每次使用这个类时都有你新增的方法,这可能是唯一的解决办法。
因为只有你的测试会用到你的方法,所以猴子补丁其实没必要,子类化 TestCase
是个合理的选择。一般来说,当你需要增强一个已有类的方法时,才会用到猴子补丁。比如,如果你想在现有的测试用例中对 TestCase.assertEqual
的调用增加一些逻辑,以便比较 Option
对象,你可以通过猴子补丁来修改 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
不过在这个例子中,看来子类化和猴子补丁都是不必要的。
假设问题是调用 self.assertEqual(firstOptions, secondOptions)
失败了,尽管 Option
实例是相等的,你其实不需要写一个新的 assertOptionsEqual
方法。你可能只需要确保你的 Option
对象正确地定义了 __eq__
方法。
所以假设你有:
class KnownGoodInputs(TestCase):
def test_good_options(self):
first, second = systemUnderTestGetOptions(...)
self.assertOptionsEqual(first, second)
那么上面 first
和 second
的类是什么呢?
对于所有Python内置类型,assertEqual
应该都能正常工作。对于自定义的 Option
类,你只需要这样做:
class Option(object): def init(self): 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
然后假设 first
和 second
是 Option
的实例,你可以这样写你的测试:
class KnownGoodInputs(TestCase):
def test_good_options(self):
first, second = systemUnderTestGetOptions(...)
self.assertEqual(first, second)