プログラムにおけるモックとは?

プログラミングにおけるモックとは、あるクラスと同じインタフェースを持つダミーのインスタンスの事を指します

どういう時に使用される?

主にテストコードの中で活用され、一部の処理をテスト用に置き換えるために使用されます。
DIとセットで活用される事が多いです。

どうやってモックを作る?

モックを作成するライブラリを活用する事をオススメします。
多くのモックを作成するライブラリは以下のような高度な検証機能を提供しています。(出来が悪いライブラリもありますが・・・)

  • メソッドの戻り値を任意の値に置き換える
    • 複数回呼び出された場合、呼び出し毎に異なる戻り値を指定できる
  • メソッドが呼び出された事を検証する(呼び出し回数の検証)
  • メソッドに渡された引数を検証する

これらの機能を自力で実装するのはなかなか骨が折れるため、ライブラリの活用をオススメします。

モックを使用したテストコードの例

以下はTypeScriptでテストフレームワーク「jest」とモック作成ライブラリ「ts-auto-mock」を使った場合の例です。

import {createMock} from 'ts-auto-mock';

describe('ExampleUseCase#exec', () => {
    it('正常に動作する事', async () => {
        // モック作成
        const bitcoinPriceReaderMock = createMock<IBitcoinPriceReader>();
        const getBitcoinPrice = bitcoinPriceReaderMock.getBitcoinPrice = jest.fn(async () => 999);

        // 処理実行
        const usecase = new ExampleUseCase(bitcoinPriceReaderMock)
        const actual = await usecase.getBitcoinPrice();

        // 確認
        assert.equal(actual, "Bitcoin Price: 999");
        expect(getBitcoinPrice.mock.calls.length).toBe(1);
    });
});

各行について、詳しく見ていきます。

const bitcoinPriceReaderMock = createMock<IBitcoinPriceReader>();

createMock関数を使って、インタフェースからモックインスタンスを生成しています。

const getBitcoinPrice = bitcoinPriceReaderMock.getBitcoinPrice = jest.fn(async () => 999);

jest.fn関数でモック関数を生成し、モックインスタンスのメソッドをモック関数に置き換えています。
この例では、999を返すモック関数に置き換えています。
(この例は少しトリッキーに見えますが、他の言語やライブラリではもっとシンプルに書けたりします)

const usecase = new ExampleUseCase(bitcoinPriceReaderMock)

テスト対象のクラスをインスタンス化します。
テスト対象のクラスがDIを採用しているため、引数にモックオブジェクトを渡します。

const actual = await usecase.getBitcoinPrice();

テスト対象の処理を実行しています。

assert.equal(actual, "Bitcoin Price: 999");

処理結果を検証しています。

expect(getBitcoinPrice.mock.calls.length).toBe(1);

モック関数が呼び出された回数を検証しています。
この例ではgetBitcoinPriceというメソッドが1回呼び出された事を検証しています。
なお、getBitcoinPrice.mock.calls[0][0]を参照すれば、各呼び出しの引数も検証できます。

GO言語の場合

GO言語のライブラリgolang/mockを使用した場合は以下のように記述できます。
以下の例ではインタフェースFooのモックインスタンスを作成し、GetHogeメソッドが呼び出される事と、第一引数に文字列Fugaが渡される事を検証しています。

m := NewMockFoo(ctrl)
m.
    EXPECT().
    GetHoge(gomock.Eq("Fuga")).
    Return(999, nil)

この様に、言語やライブラリにより、多少書き方が異なりますが、出来ることは概ね同じですので、恐れず活用していきましょう。

次に読むべき記事

DI(Dependency Injection・依存性の注入)とは?
プログラムにおける副作用(Side Effect)とは?

「プログラムにおけるモックとは?」への2件のフィードバック

コメントする