Help us understand the problem. What is going on with this article?

Jest のモック関数について整理する

More than 3 years have passed since last update.

Jestを使ったテストを行うとき、 Mock Functions を駆使してテストすることになる。
ここでは公式サイトの記述を少し意訳しながらまとめておく。

意訳の狙いは、次の二つ。

  • テストコードを書くときに、なぜ mock function が必要かということがわかるように
  • テストコードを読むときに登場する mock function に混乱しないように

mock functions

mock function は、あるモジュールとそれ以外のモジュール(あるモジュール内の関数が、APIとして使いたい関数が定義されている)との関連性をテストする時に、テストの複雑さを軽減するために使われる

mock functions は今テストしない側の関数呼び出しやコンストラクタ呼び出しをキャプチャするので、テストしたい関数が正しくAPIを使っているかを、実際のAPI、モジュールがなくても検証できるようになる。そして、これらのAPIについてテスト時の戻り値を制御することができる。つまり今やりたいテストに集中し、その他を簡略化するようなテストコードを記述できるようになる。

また、大きく2つの方法で mock function を生成することができる。
* require()ing a mocked components
* explicitly requesting one from jest.genMockFunction()

// The function was called exactly once
expect(someMockFunction.mock.calls.length).toBe(1);

// The first arg of the first call to the function was 'first arg'
expect(someMockFunction.mock.calls[0][0]).toBe('first arg');

// The second arg of the first call to the function was 'second arg'
expect(someMockFunction.mock.calls[0][1]).toBe('second arg');

.mock property

mocked function がどのように呼び出されてきたかを示すデータを .mockプロパティに持っている。
.mockプロパティはコンテキストthisの値も追跡しているので、それを検証することもできる。

var myMock = jest.genMockFunction();

var a = new myMock(); // myMock関数内の this は a
var b = {};
var bound = myMock.bind(b); // myMock関数内の this は b
bound();

console.log(myMock.mock.instances);
> [ <a>, <b> ]

Mock Return Values

Mock function は、テスト用の値を inject することもできる。リアルに値を計算しなくても直接戻り値を指定することができるので、関数を引数に取る関数をテストするときも便利。この仕組みを使うと、本物同等の複雑なスタブを用意する必要がなくなる。この仕組みを駆使して、テストに関係ない関数のロジックを実装しないことがコツとなる。

var myMock = jest.genMockFunction();
console.log( myMock() );
> undefined

myMock.mockReturnValueOnce(10)
 .mockReturnValueOnce('x')
 .mockReturnValue(true);

console.log(myMock(), myMock(), myMock(), myMock());
> 10, 'x', true, true

Mock Implementations

チェーンするような関数の mock が必要な場合は、次のようなシンタックスシュガーが使える。

var myObj = {
  myMethod: jest.genMockFunction().mockReturnThis()
};

// is the same as

var myObj = {
  myMethod = jest.genMockFunction().mockImplementation(function() {
    return this;
  });
};

Custom Matchers

assert がより簡潔に記述できるように、 custom mathchers が用意されている。これらは基本的に .mock property を使って新たな関数を定義しているだけなので、必要に応じて自作することもできる。

//Cutome mathchers
// The mock function was called at least once
expect(mockFunc).toBeCalled();

// The mock function was called at least once with the specified args
expect(mockFunc).toBeCalledWith(arg1, arg2);

// The last call to the mock function was called with the specified args
expect(mockFunc).lastCalledWith(arg1, arg2);

// Using plain mock functions APIs to expect something
// The mock function was called at least once
expect(mockFunc.mock.calls.length).toBeGreaterThan(0);

// The mock function was called at least once with the specified args
expect(mockFunc.mock.calls).toContain([arg1, arg2]);

// The last call to the mock function was called with the specified args
expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual(
  [arg1, arg2]
);

// The first arg of the last call to the mock function was `42`
// (note that there is no sugar helper for this specific of an assertion)
expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42);

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした