14

静的なプログラミング言語のバックグラウンドから来て、Pythonでモックを作成するのに最適な方法を考えています。私は依存性注入に慣れています。テスト内で、モックが作成され、テスト対象システム(SUT)に渡されます。ただし、Python用のモックおよびその他のモックフレームワークを見ると、タイプ/関数などが表示されます。モジュール内のは、テストごとに置き換えられます。

@patch('some.type.in.the.module.under.test')特に、モックでは、各ユニットテストの上に、タイプ/機能などごとに言います。あなたは嘲笑したい。テストの存続期間中、それらはモックされ、その後元に戻されます。残念ながら、テスト全体で、フィクスチャはほぼ同じであり、@patchesを何度も繰り返すことになります。

単体テスト間でパッチのコレクションを共有する方法が必要です。また、構成可能な方法でフィクスチャに微調整を加えたいと思います。デコレータの代わりにコンテキストマネージャを使用しても大丈夫です。

4

4 に答える 4

12

そのクラスの各メソッドに流れるテスト クラスにパッチを適用できます。そして、スーパー クラスから継承して、setUp メソッドと TeaDown メソッドを操作できます。

import unittest 

@patch('some.type.in.the.module.under.test')
class MySuperTestCase(unittest.TestCase):
    pass

class MyActualTestCase(MySuperTestCase):

    def test_method(self, mock_function)
        mock_function.return_value = False

しかし、これはあなたが思っているほど一般的ではありません。オブジェクトが使用されている正確な場所でオブジェクトにパッチを適用する必要があるためです。「sys.stdout」にパッチを当てるのではなく、「my_dir.my_module.sys.stdout」にパッチを当てます。したがって、特定のモジュールをテストする場合にのみ使用できます。しかし、その特定のモデルをテストするには、1 つのパッチ デコレータしか必要ないことは確かです。

于 2012-07-26T08:07:21.310 に答える
5

私は最近、同様の状況に遭遇しましたが、より極端です。私の最上位モジュールの 1 つは、いくつかのリポジトリ、プロバイダー、およびロジック ライブラリをモック化する必要がありました。@patchこれにより、 7 つのコンポーネントに必要な多数の単体テストが発生しました。多くの重複したテストコードを避けたかったので、かなりうまく機能した私のソリューションは次のとおりです。

@mock.patch('module.blah1.method1')      # index: 6
@mock.patch('module.blah1.method2')      # index: 5
@mock.patch('module.blah2.method1')      # index: 4
@mock.patch('module.blah2.method2')      # index: 3
@mock.patch('module.blah2.method3')      # index: 2
@mock.patch('module.blah3.method1')      # index: 1
@mock.patch('module.blah4.method1')      # index: 0
class TestsForMyCode(unittest.TestCase):

    def test_first_test(self, *mocks):
        # Arrange

        # setup mocks for only the ones that need specific mocked behaviours

        # idx 2 patches module.blah2.method3
        mocks[2].return_value = 'some value'

        # Act
        target = sut()
        result = target.do_something()

        # Assert
        assert result is False

    def test_second_test(self, *mocks):
        # Arrange

        # setup mocks for only the ones that need specific mocked behaviours

        # idx 0 patches module.blah4.method1
        mocks[0].return_value = 'another value'

        # idx 4 patches module.blah2.method1
        mocks[4].return_value = 'another value'

        # Act
        target = sut()
        result = target.do_something_else()

        # Assert
        assert result is True

クラスの@mockは、実行時に各テストに適用され、すべてのパッチを *mocks パラメータに渡します。覚えておくべき重要なことは順序付けです。頭の中でまっすぐに保つために、インデックス コメントをコードに配置します。

お役に立てれば。

于 2014-08-23T01:41:17.540 に答える
1

テストする方法がないため、これが構文的に正しいとは限りませんが、次のようになります。

COMMON_FUNCTIONS = ('some.type.in.the.module.under.test', 'and.others')
def common_patches(f):
    for item in COMMON_FUNCTIONS:
        f = patch(item)(f)

次のように適用します。

@common_patches
def something():
    pass # it will be decorated by all the patches in the function
于 2012-07-25T20:04:41.567 に答える