これは私が長い間苦労してきたことですが、ようやく解決策を見つけたと思います。
既にお気付きのように、基本クラスをモックに置き換えようとすると、テストしようとしているクラスが単にモックになり、それをテストする能力が失われます。解決策は、基本クラス全体ではなく、基本クラスのメソッドのみをモックすることですが、これは言うは易く行うは難しです。テストごとにすべてのメソッドを 1 つずつモックすると、エラーが発生しやすくなる可能性があります。
私が代わりに行ったのは、別のクラスをスキャンするクラスを作成し、それ自体Mock()
に他のクラスのメソッドに一致する s を割り当てることです。その後、テストで実際の基本クラスの代わりにこのクラスを使用できます。
偽のクラスは次のとおりです。
class Fake(object):
"""Create Mock()ed methods that match another class's methods."""
@classmethod
def imitate(cls, *others):
for other in others:
for name in other.__dict__:
try:
setattr(cls, name, Mock())
except (TypeError, AttributeError):
pass
return cls
したがって、たとえば、次のようなコードがあるかもしれません (これは少し不自然で申し訳ありBaseClass
ません。SecondClass
と は重要な作業を行っており、多くのメソッドが含まれており、必ずしもあなたによって定義されているとは限りません):
class BaseClass:
def do_expensive_calculation(self):
return 5 + 5
class SecondClass:
def do_second_calculation(self):
return 2 * 2
class MyClass(BaseClass, SecondClass):
def my_calculation(self):
return self.do_expensive_calculation(), self.do_second_calculation()
次に、次のようないくつかのテストを作成できます。
class MyTestCase(unittest.TestCase):
def setUp(self):
MyClass.__bases__ = (Fake.imitate(BaseClass, SecondBase),)
def test_my_methods_only(self):
myclass = MyClass()
self.assertEqual(myclass.my_calculation(), (
myclass.do_expensive_calculation.return_value,
myclass.do_second_calculation.return_value,
))
myclass.do_expensive_calculation.assert_called_once_with()
myclass.do_second_calculation.assert_called_once_with()
したがって、基本クラスに存在するメソッドは、対話可能なモックとして引き続き使用できますが、クラス自体はモックにはなりません。
そして、これが python2 と python3 の両方で機能するように注意しました。