私は別のクラスを使用しているクラスをテストしているこの種の設定を持っています、そして私は後者を模擬したいので最初のクラス自体だけをテストしています。
nuclear_reactor.py
:
class NuclearReactor():
def __init__(self):
print "initializing the nuclear reactor"
def start(self):
print "starting the nuclear reactor"
nuclear_manager.py
:
from nuclear_reactor import NuclearReactor
class NuclearManager():
def __init__(self):
print "manager creating the nuclear reactor"
self.reactor = NuclearReactor()
def start(self):
print "manager starting the nuclear reactor"
self.reactor.start()
test_nuclear_manager.py
:
from mock import Mock
import nuclear_manager
from nuclear_manager import NuclearManager
def test():
mock_reactor = nuclear_manager.NuclearReactor = Mock()
nuke = NuclearManager()
nuke.start()
nuke.start()
print mock_reactor.mock_calls
print mock_reactor.start.call_count
test()
テストしたいのは、NuclearReactor.start
が呼び出されることですが、これを実行すると、次のようになります。
manager creating the nuclear reactor
manager starting the nuclear reactor
manager starting the nuclear reactor
[call(), call().start(), call().start()]
0
start
はインスタンスの属性であり、クラスの属性ではないので完全に理解できます。mock_calls
を解析することはできますが、インスタンス化された呼び出しを確認するより良い方法はありません偽のクラスが作られる?
NuclearManager
で依存性注入を使用してモックNuclearReactor
を渡すことができますが、モックだけを使用する別の方法があると考えています。
実際、start
が呼び出されているかどうかをテストしていますクラスで直接が呼び出されていますが、コードでは呼び出されていません。インスタンスのメソッドを直接テストできます。インスタンスはクラスを呼び出すことによって生成されることに注意してください。
_print mock_reactor.return_value.calls
print mock_reactor.return_value.start.call_count
_
_Mock.return_value
_属性 は、モックされたクラス、つまりインスタンスの呼び出しの結果です。
単にcallモックにすることもできます。デフォルトでは、モックは呼び出されたときに常にまったく同じオブジェクトを返し、新しいモックはその戻り値を表します。
_print mock_reactor().calls
print mock_reactor().start.call_count
_
モックインスタンスとモックインスタンスの_return_value
_属性を呼び出した結果は、まったく同じです。
NuclearReactor
モックへの呼び出しを出力することにより、すでに正しいパスにいたので、_calledモックでstart()
が呼び出された詳細を見逃しました。 call().start()
ではなくstart()
が記録されました。
直接割り当てではなく、 mock.patch()
を使用してパッチを処理することもできます。これにより、パッチが削除済みであることを確認し、他のテストがモック対象を独自に決定できるようにします。
_import mock
from nuclear_manager import NuclearManager
@mock.patch('nuclear_manager.NuclearReactor')
def test(mock_reactor):
nuke = NuclearManager()
nuke.start()
nuke.start()
instance = mock_reactor.return_value
assert instance.start.call_count == 2
instance.assert_called()
_
ここではデコレータとして使用しました。 test()
関数が呼び出されるとモックが配置され、関数が終了すると再び削除されます。 patch()
をコンテキストマネージャとして使用して、パッチの範囲をさらに細かく制限することもできます。
また、このようなユニットテストでは、 unittest
library を使用してください。
_import mock
import unittest
import nuclear_manager
class NuclearManagerTests(unittest.TestCase):
@mock.patch('nuclear_manager.NuclearReactor')
def test_start(self, mock_reactor):
nuke = NuclearManager()
nuke.start()
nuke.start()
instance = mock_reactor.return_value
self.assertEqual(instance.start.call_count, 2)
instance.assert_called()
if __name__ == '__main__':
unittest.main()
_
これにより、テストをより大きなテストスイートに適合させ、テストを有効または無効にして、他のテストツールと統合できます。