5

Pythonに厳密なモックに相当するものはありますか? モック化されたメソッド (この例では action.step2()) の意図しない呼び出しを報告するメカニズム。これは GoogleMock フレームワークの場合とまったく同じです。

class Action:
    def step1(self, arg):
        return False

    def step2(self, arg):
        return False

def algorithm(action):
    action.step1('111')
    action.step2('222')
    return True

class TestAlgorithm(unittest.TestCase):
    def test_algorithm(self):
        actionMock = mock.create_autospec(Action)
        self.assertTrue(algorithm(actionMock))
        actionMock.step1.assert_called_once_with('111')
4

3 に答える 3

5

初期状態ではサポートされていないようです。ただし、同じ結果を得る方法については、少なくとも 2 つのアプローチがあります。

許可されたメンバーの受け渡しリスト

モックドキュメントによると

spec : これは、文字列のリストまたはモック オブジェクトの仕様として機能する既存のオブジェクト (クラスまたはインスタンス) のいずれかです。オブジェクトを渡すと、オブジェクトで dir を呼び出すことによって文字列のリストが形成されます (サポートされていないマジック属性とメソッドを除く)。このリストにない属性にアクセスすると、 AttributeError が発生します。

したがって、テスト例を失敗させるには、単に置き換えます

actionMock = mock.create_autospec(Action)

actionMock = mock.Mock(spec=['step1'])

このようなアプローチには、クラスまたはインスタンスをspec引数として渡す場合と比較して、特定の欠点があります。許可されているすべてのメソッドを渡し、それらに期待を設定して、それらを効果的に 2 回登録する必要があるためです。また、メソッドのサブセットを制限する必要がある場合は、それらを除くすべてのメソッドのリストを渡す必要があります。これは次のようにして実現できます。

all_members = dir(Action)  # according to docs this is what's happening behind the scenes
all_members.remove('step2')  # remove all unwanted methods 
actionMock = mock.Mock(spec=all_members)

制限されたメソッドに例外を設定する

別のアプローチは、呼び出されたくないメソッドに明示的に失敗を設定することです。

def test_algorithm(self):
    actionMock = mock.create_autospec(Action)
    actionMock.step2.side_effect = AttributeError("Called step2") # <<< like this
    self.assertTrue(algorithm(actionMock))
    actionMock.step1.assert_called_once_with('111')

これにはいくつかの制限もあります。エラーと期待値を設定する必要があります。

最後に、この問題に対する根本的な解決策の 1 つは、パッチを適用してコンストラクターにパラメーターをmock追加し、プル リクエストを送信することです。それが受け入れられるか、メンテナーがそれを達成する方法を指摘するよりも。:)strictMockmock

于 2014-07-09T06:37:40.793 に答える
0

別の可能性:

制限されたメソッドで call_count を個別にチェックする

call_count呼び出してはならないメソッドで が 0 であることを確認してください。

class TestAlgorithm(unittest.TestCase):
    def test_algorithm(self):
        actionMock = mock.create_autospec(Action)
        self.assertTrue(algorithm(actionMock))
        actionMock.step1.assert_called_once_with('111')
        self.assertEqual(actionMock.step2.call_count, 0) # <<< like this

欠点は、すべての予期しない呼び出しを 1 つずつ確認する必要があることです。

于 2014-07-10T21:18:59.757 に答える
0

はい、これはspec=およびautospec=引数を使用して可能です。詳細については、Autospeccing のモック ドキュメントを参照してください。あなたの例では、次のようになります。

action_mock = mock.Mock(spec=Action)

また:

action_mock = mock.Mock('Action', autospec=True)
于 2014-07-08T13:36:16.333 に答える