HOWTO · Python

Python モック インポート

この記事では、Python Mock Import の使用方法を示します。

このページの内容

この Python 記事では、mock ライブラリを調べて、それを効果的に使用する方法を学びます。 簡単な例から始めて、より高度な使用法を見ていきます。

mock オブジェクトとモックの使い方と落とし穴を学びます。

Python モック インポート

Python の mock ライブラリは、ユニット テスト用の最も一般的なライブラリの 1つです。 これにより、システムの一部をモック オブジェクトに置き換えて、それらが期待どおりに使用されていることをアサートできます。

モッキングは強力なツールですが、よく誤解されています。 この記事では、モッキングとは何か、その使用方法、およびいくつかの一般的な落とし穴について説明します。

Python でのモック

モッキングとは、本物のオブジェクトを偽のオブジェクトに置き換えるプロセスです。 偽のオブジェクトはモックと呼ばれます。

モッキングを使用すると、コードがシステムの他の部分と実際に依存することなく、どのように対話するかをテストできます。 たとえば、データベースをモックして、データベースがなくてもコードがどのように対話するかをテストできます。

Python でモックを使用する方法

モッキングは、次の 2つの異なる目的で使用できます。

  1. コードの動作をテストするには

    たとえば、データベースをモックして、コードがデータベースを正しくクエリしていることをアサートできます。

  2. テストしたくない動作をスタブ化する

    たとえば、データベースへの接続を回避するためにデータベースをモックする場合があります。

モッキングを使用する目的によって、モッキングの使用方法が決まります。

テスト動作

モックを使用して動作をテストする場合、コードが期待どおりにモック オブジェクトと対話することをアサートしたいと考えています。 コードがモックであることを認識しないように、モック オブジェクトは実際のオブジェクトと同じインターフェイスを持つ必要があります。

assert_called_with() メソッドを使用して、想定される引数でモック メソッドが呼び出されたことをアサートできます。 たとえば、データベースをモックしている場合、query() メソッドが正しい SQL で呼び出されたと断言できます。

assert_called() メソッドを使用して、モック メソッドが呼び出されたことをアサートすることもできます。 これは、引数を気にしない場合や、引数が複雑で主張が難しい場合に役立ちます。

スタブアウト動作

モックを使用して動作をスタブ化する場合、期待する値を返すようにモック オブジェクトを構成する必要があります。 たとえば、データベースをモックしている場合、query() メソッドを構成してダミー データのリストを返すことができます。

side_effect 属性を使用して、モック オブジェクトを構成できます。 side_effect は、関数を含む任意の値にすることができます。

モックが呼び出されると、side_effect が返されます。

たとえば、side_effect を使用して、モックが呼び出されるたびに異なる値を返すことができます。 これは、エラーやさまざまな動作をシミュレートするのに役立ちます。

side_effect を使用して例外を発生させることもできます。 これは、エラーのシミュレーションに役立ちます。

Python でのモックの一般的な落とし穴

モッキングを使用する場合、いくつかの一般的な落とし穴があります。

  1. 1つの落とし穴は、あざけりすぎることです。 モッキングは強力なツールですが、万能薬ではありません。

    モックは、システム全体の動作ではなく、コードの動作をテストする場合に最も役立ちます。

    あまりにも多くのモックを作成しようとすると、最終的に多くのモック オブジェクトが作成され、テストの保守が難しくなります。 必要なオブジェクトのみをモックし、残りのオブジェクトには実際のオブジェクトを使用することをお勧めします。

  2. もう 1つの落とし穴は、適切でないときにモッキングを使用することです。 モッキングは、コードの分離された部分をテストするときに最も役立ちます。

    システム全体をテストする場合は、通常、統合テストを使用することをお勧めします。 統合テストは、システム全体を実行するテストであり、実行に時間がかかり、コストがかかりますが、より正確です。

  3. 最後に、よくある間違いは、偽物を使用すべきときにモックを使用することです。 偽のオブジェクトは、実際のオブジェクトを模倣するが、同じインターフェイスを持たないオブジェクトです。

たとえば、偽のデータベースは、実際のデータベースに接続する代わりに、ハードコーディングされたデータを返す場合があります。 フェイクは動作をスタブ化するのに役立ちますが、動作のテストにはあまり役立ちません。

Python でのモックの基本的な使い方

モックの最も基本的な使い方は、オブジェクトをモック オブジェクトに置き換えることです。

たとえば、オブジェクトを引数として取り、それに対して何かを行う関数があるとします。 たぶん、オブジェクトの名前を出力します。

コード例:

def print_name(obj):
    print(obj.name)

この関数をテストしたい場合は、name 属性を持つオブジェクトを作成し、それを関数に渡すことができます。

コード例:

class TestObject:
    def __init__(self, name):
        self.name = name


obj = TestObject("Abid")
print_name(obj)

出力:

Abid

コードは機能し、名前が Abid として出力されていることがわかります。 しかし、それにはいくつかの欠点があります。

まず、テストのためだけに実際のオブジェクトを作成する必要があります。 これは、この単純な例では大したことではないかもしれませんが、より複雑なシステムでは、テストのためだけに必要なオブジェクトをセットアップするのは大変な作業になる可能性があります。

第二に、このアプローチはあまり柔軟ではありません。 さまざまな動作をテストするには、毎回新しい実オブジェクトを作成する必要があります。

たとえば、オブジェクトに name 属性がない場合に何が起こるかをテストしたい場合はどうすればよいでしょうか?

コード例:

class TestObject:
    def __init__(self, name):
        self.name = name


obj = TestObject()
print_name(obj)

実際のオブジェクトでは、エラーが発生します。 しかし、テスト オブジェクトを使用すると、コードの出力はコードに欠けているものになります。

出力:

__init__() missing 1 required positional argument: 'name'

Python モック インポートの使用方法

テスト目的でモック インポートを操作するには、モック オブジェクトを作成して調べてみましょう。

まず、mock ライブラリをインポートする必要があります。 mock ライブラリは、モック オブジェクトを作成できる mock クラスを提供します。

ライブラリをインポートした後、mock クラスを呼び出して出力し、このモック オブジェクトがどのように見えるかを確認します。

コード例:

from unittest.mock import Mock

mock = Mock()
print(mock)

出力:

<Mock id='139754809551888'>

コードの出力は、ID id='139754809551888' の数値文字列を持つモック オブジェクトの表現を示しています。

では、このモック オブジェクトで何ができるか、どのように使用できるかを調べてみましょう。 モック オブジェクトは通常、コード内の他のオブジェクトにパッチを適用するために使用されます。

パッチと言うとき、それは置き換える、模倣する、またはモックすることを意味します。 それらはすべて同じです。

モッキングの本質は、可能な限り本物に近いものを置き換えることです。 また、模擬テストを実行するときは、制御された環境で行うことを忘れないでください。

したがって、外部の品位によって模擬テストが失敗することはありません。

コードに外部依存関係があるとしましょう。 外部依存の例として、json を使用してみましょう。

また、制御が難しく、テストで必ずしも発生させたくない動作があります。

できることは、モック オブジェクトを使用してこの依存関係にパッチを当てることです。 そのため、まず、json ファイル形式をインポートする必要があります。

次に、JSON の json.dumps メソッドを使用して、辞書を関連付けます。 したがって、外部依存メソッドのメソッドを使用しているだけです。

次に、json = mock を使用して JSON にパッチを適用します。モック オブジェクトにはダム オブジェクトはありません。 これを証明するには、json のディレクトリを出力する必要があります。

コード例:

import json

data = json.dumps({"a": 1})
json = mock
print(dir(json))

出力:

['assert_any_call', 'assert_called', 'assert_called_once', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'dumps', 'getdoc', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect']

モック オブジェクトに関連付けられた出力として、オブジェクトとメソッドの文字列を確認できます。 また、dumps はコード出力のメソッドの 1つではないことに注意してください。

テストにおける Python の依存関係

単体テストを作成している関数が、request モジュールや日時などの依存関係を使用している場合。 次に、単体テストが、テストされている関数から常に同じ出力を取得するとは限らない可能性があります。

request ライブラリを使用していくつかの HTTP リクエストを作成する関数があるとします。 したがって、インターネット接続なしで単体テストを実行すると、失敗し、request ライブラリから接続エラーが発生します。

そのため、制御された環境でコードをテストして、予測できない依存関係を制御することをお勧めします。そこでは、依存関係への実際の呼び出しをモック オブジェクトに置き換えることができます。 これにより、その依存関係の動作を微調整できます。

たとえば、実際の HTTP リクエストを作成する代わりに、request.get() 関数の呼び出しで返されるダミーの HTTP レスポンスを提供できます。

依存関係もスプーフィングされます。これは、モック オブジェクトが参照可能なユーザーに関する情報を持っているためです。

たとえば、呼び出した場合、何回呼び出したか、特定の依存関係を何回呼び出したかなどです。 したがって、これはより堅牢な単体テストを作成するのに役立ちます。

そこで、テストのために Python でオブジェクトをモックする方法を探ります。

Python mock オブジェクト

Python モック オブジェクトをよりよく理解するために、2つの Python スクリプトに取り組みます。

  1. roll_dice_function
  2. roll_dice_functionのモック

そこで、ランダムな値を生成するコードに取り組みます。 ある数値と別の数値の間の整数を返す単純な roll_dice_function があります。

そして、両方の数値を関数 roll_dice_function に提供します。

コード例:

# import library
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)

そのため、最初にライブラリをインポートします。 次に、def キーワードを使用して関数を定義します。

この関数は、5 から 10 までの整数を返します。これは、random モジュールの random.randint 関数を使用します。

roll_dice_function のコードが完成したら、モック オブジェクトを使用して roll_dice_function をテストする別のコードを記述します。 先に進みましょう。

まず、mock のテスト ライブラリをインポートする必要があります。

# import library
from unittest.mock import Mock
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)

それがどのように機能するか見てみましょう。 ここで、先ほど作成した roll_dice_function の機能について考えてみましょう。

したがって、関数を呼び出すたびに、5 から 10 までの乱数を取得します。

コード例:

# import library
from unittest.mock import Mock
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)


roll_dice_function()

出力:

The number is....
7

コードをもう一度実行して、今度はどのような数値が得られるか見てみましょう。

出力:

The number is....
5

したがって、関数を呼び出すたびに、5 から 10 の間で生成された乱数を取得します。

ここで、モックを使用して、呼び出すたびに関数が同じ値を返すようにします。

mock オブジェクトを作成する

mock オブジェクトを作成するには、mock ライブラリで定義されたモック クラス オブジェクトを作成する必要があります。

コード例:

mock_roll_object = mock.Mock()

ここで、モック オブジェクト mock_roll_object を呼び出します。

mock_roll_object = mock.Mock()
mock_roll_object

出力:

<Mock name='mock.Mock()' id='139883130268416'>

これは、モック オブジェクトを呼び出すと、出力がモック オブジェクトとして取得されることを示しています。 したがって、これは一般的なモック オブジェクトに関することです。 モック オブジェクトを呼び出すたびに、出力としてモック オブジェクトが得られます。

簡単にするために、モック オブジェクトでいくつかのことを定義できます。 デバッグ目的で、name を定義できます。

コード例:

mock_roll_object = mock.Mock(name="mocking roll dice")

そのため、単体テストをデバッグしようとすると、その名前が表示され、デバッグに役立ちます。

出力:

<Mock name='mocking roll dice' id='139883130347136'>

私たちのモックの名前は、ここでは mocking roll dice です。

ここで、特定の値を返したい場合は、その値を return_value に代入する必要があります。 したがって、モック オブジェクトを呼び出すたびに同じ番号が取得されます。

コード例:

mock_roll_object = mock.Mock(name="mocking roll dice", return_value=8)

次に、オブジェクトを呼び出します。

mock_roll_object()

出力:

8

モック オブジェクトを呼び出すたびに 8 を取得します。 return_value に 8 を割り当てたので、同じ戻り値が得られます。

この Python の記事が、Python で Mock を使用する方法を理解するのに役立つことを願っています。