[英]Writing unittests for abstract classes
考虑这个例子:
class A:
def do_stuff(self):
# ...
some_var = self.helper_method()
# ...
def helper_method(self):
# This method must be implemented by subclass
raise NotImplementedError()
class B(A):
def helper_method(self):
# implementation for class B
class C(A):
def helper_method(self):
# implementation for class C
我的任务是为A
, B
和C
类编写单元测试(特别是对于do_stuff
)。
但是,如果我不能直接使用它的一些方法,我如何测试A
类? 我应该只测试B
和C
类(它们有helper_method
实现),还是可以在Python中测试抽象类?
你没有真正的抽象基类,至少就语言而言。 没有什么能阻止你实例化它。
a = A()
如果您使用abc
模块来定义无法实例化的类:
class A(metaclass=abc.ABCMeta):
...
那么你可以通过覆盖它的一组抽象方法来使A
实例化:
A.__abstractmethods__ = frozenset()
a = A()
# test away
在任何一种情况下,您仍然可以测试抽象方法是否引发NotImplementedError
try:
a.helper_method()
except NotImplementedError:
print("Test passed")
else:
print("Test failed")
或根据需要测试其默认实现。
do_stuff
存在于A
,因此请在A
上进行测试。 辅助方法存在于具体类中,因此在那里进行测试。 您可以使用unittest.mock
模块临时修补抽象类,以便它可以与您的测试一起使用,还可以修补抽象方法以返回特定值 - 这样它的逻辑就不会受到测试。 鉴于这一切,这就是我测试抽象类的方法。
鉴于一些抽象类:
from abc import abstractmethod, ABC
class MyAbstract(ABC):
def concrete_method(self):
i = self.abstract_method()
return i ** 2
@abstractmethod
def abstract_method(self):
"""return some int"""
pass
这是我测试它的方式。
from unittest import main, TestCase
from unittest.mock import patch, Mock
from module_under_test import MyAbstract
class TestMyAbstract(TestCase):
def test_cannot_instantiate(self):
"""showing we normally can't instantiate an abstract class"""
with self.assertRaises(TypeError):
MyAbstract()
@patch.multiple(MyAbstract,
__abstractmethods__=set(),
abstract_method=Mock(return_value=3))
def test_concrete_method(self):
"""patch abstract class and its abstract methods for duration of the test"""
# given
my_abstract = MyAbstract()
expected = 9
# when
actual = my_abstract.concrete_method()
# then
self.assertEqual(actual, expected)
if __name__ == "__main__":
main()
你应该测试逻辑,而不是实现。 A的do_stuff()方法本身没有逻辑,对吗? 它的作用取决于你是在处理B还是C.相反,在我看来,测试B和C的do_stuff()方法会更有意义 - 你知道它们应该做什么。
由于@chepner已经回答了你的问题,不是为了离题,但是你应该尽量避免在Python中使用抽象类。 抽象类不会或不应该在Dynamic DuckTyped语言(例如Python,Ruby等)中用于太多目的。在Duck类型中,只要特定实例响应特定行为,就不应强制它成为孩子一个特定的抽象类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.