「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > Python クラスのモック化

Python クラスのモック化

2024 年 11 月 3 日に公開
ブラウズ:297

Mocking Python Classes

最近、Python モジュールの Pytest を使用して単体テストを作成する必要がありました。モジュールには、コンストラクター内で他のクラスが初期化されるクラスが含まれています。

いつものように、各クラス メソッドのテストを簡単に作成できるように、このクラスのフィクスチャを作成しました。この時点で、コンストラクターで開始されたさまざまなクラスをモックしようとしたときに、いくつかの問題に遭遇しました。モックは機能せず、これらのクラスのインスタンスはまだ作成されていました。

いくつかの調査を行い、オンラインで見つけたいくつかの異なるソリューションを組み合わせた後、クラスを模擬する方法を共有したいと思います。

解決

これが私がモックしようとしたクラスの例です:

class ClassA:
    def __init__(self):
        self.class_b = ClassB()
        self.class_c = ClassC()
        self.count = 0

テスト中にこのクラスのすべてのフィールドに値を設定したいと考えています。この値は None またはクラス モックにすることができますが、クラス ClassB と ClassC の開始は望ましくありません。

私たちの場合、self.class_b と self.class_c をモックにすることにしましょう:

@pytest.fixture
def mock_class_b():
    class_b = Mock(spec=ClassB)
    return class_b

@pytest.fixture
def mock_class_c():
    class_c = Mock(spec=ClassC)
    return class_c

したがって、私たちの目的を果たすこのクラスのフィクスチャは次のようになります:

@pytest.fixture
def class_a_mock(mock_class_b, mock_class_c):
    with patch.object(target=ClassA, attribute="__init__", return_value=None) as mock_init:
        class_a = ClassA()
        class_a.class_b = mock_class_b
        class_a.class_c = mock_class_c
        class_b.count = 0
        return class_a

重要な部分は、Python の Unittest.mock モジュールにある patch.object 関数の使用方法です。これは、特定のオブジェクトの属性をモックまたは別の値に一時的に置き換えるためのテストで使用されます。

引数

  1. target=ClassA: 属性をパッチしたいオブジェクト (通常はクラス)。
  2. attribute="__init__": パッチを適用する属性の名前。
  3. return_value=None: __init__ メソッドを何も行わない関数に置き換えます

このようにして、フィクスチャ内にモック化された変数を作成できます。
patch.object

について詳しく読む

テストのヒント

このチュートリアルは、何らかの理由でクラス A のコードを変更できない場合に備えて作成しました。ただし、一般的には、ロジックを変更するのではなく、よりテストしやすくするために、可能であればコードを変更することをお勧めします。 .

クラス A を変更してテストしやすくする方法の例をいくつか示します:

オプション 1: クラス B とクラス C のインスタンスをパラメータとして渡します。
こうすることで、フィクスチャを作成するときに、インスタンスの代わりにモックを渡すことができます。

class ClassA:
    def __init__(self, class_b_instance, class_c_instance):
        self.class_b = class_b_instance
        self.class_c = class_c_instance
        self.count = 0

オプション 2: テスト モードを示すブール変数を作成します。
このようにして、クラス A のどのフィールドが開始時に値を取得するか取得しないかを決定できます。

class ClassA:
    def __init__(self, test_mode=False):
        if not test_mode:
            self.class_b = ClassB()
            self.class_c = ClassC()
        self.count = 0

オプション 3: 別のメソッドでクラスを開始します。
このアプローチにより、テスト モジュールで set_class_variables の呼び出しを回避するという選択肢が得られます。

class ClassA:
    def __init__(self):
        self.class_b = None
        self.class_c = None
        self.count = None

    def set_class_variables(self):
        self.class_b = ClassB()
        self.class_c = ClassC()
        self.count = 0

これがお役に立てば幸いです! :)

リリースステートメント この記事は次の場所に転載されています: https://dev.to/chen_ashkenazi/mocking-python-classes-4h96?1 侵害がある場合は、[email protected] に連絡して削除してください。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3