あいつの日誌β

働きながら旅しています。

sinon.js を自習メモ

あらすじ

sinon.js の使い方を毎回 Google 先生に何でしたっけ?って聞くので自分のブログに書いておきます。 せっかくなので覚えたての jsdom も使いたいと思います。

引用元

この記事は下記を自分向けに編集したものです。

準備

% mkdir practice-sinon && cd $_
% npm init -f && npm install sinon jsdom jquery w3c-xmlhttprequest babel mocha power-assert --save-dev

create: test/browser.js

import jsdom from 'jsdom';
import jQuery from 'jquery';
import { XMLHttpRequest } from 'w3c-xmlhttprequest';

global.XMLHttpRequest = XMLHttpRequest;
global.window = jsdom.jsdom('<!doctype html><html><body></body></html>').defaultView;
global.document = global.window.document;
global.$ = jQuery(global.window);

create: test/test_sinon.js

import './browser';
import sinon from 'sinon';
import assert from 'power-assert';

describe('FakeServer in node.js', () => {

  let server;
  let spy;

  beforeEach(() => {
    server = sinon.fakeServer.create();
    spy = sinon.spy();
  });

  afterEach(() => {
    server.restore();
  });

  it('should return fake response', () => {
    server.respondWith('GET', '/sample.json', [
      200,
      { 'Content-Type': 'application/json' },
      JSON.stringify({message: 'Hello World'})
    ]);
    $.getJSON('/sample.json').then((data) => {
      spy(data);
    });
    server.respond();
    assert.ok(spy.calledWith({message: 'Hello World'}));
  });
});

実行

% $(npm bin)/mocha --compilers js:babel/register



  FakeServer in node.js
    ✓ should return fake response


  1 passing (51ms)

Sinon.js について

以下の機能が存在します

  • spy: 関数がどのように呼び出されたかを記録する
  • stub: 関数の戻り値をあらかじめ設定し、その結果でテストを行う
  • mock: 実行前に関数の実行回数など期待する結果を指定しておく
  • fake server: 問い合わせるDBやサーバ処理などを単純な実装に置き換える

spy

spy で行うこと

  • スパイオブジェクトを作成し、関数を監視する
  • 監視対象の関数を実行する
  • スパイオブジェクトを確認する
  • スパイオブジェクトをクリアする

stub

割愛

mock

割愛

fake

test/test_sion.js

import './browser';
import sinon from 'sinon';
import assert from 'power-assert';

describe('FakeServer in node.js', () => {

  it('spy', () => {
    let spy = sinon.spy($, "ajax");
    $.getJSON("/some/resource")
    assert.ok(spy.calledOnce , "method is called once");
    assert.equal(spy.getCall(0).args[0].url, "/some/resource", "url parameter");
    assert.equal(spy.getCall(0).args[0].dataType, "json", "dataType parameter");
    $.ajax.restore();
  });

  class Human {
    constructor(name) {
      this.name = name
    }
    hello(friendName) {
      return "hello, " + friendName + ". I'm " + this.name + ".";
    }
  }

  it('stub', () => {
    let human = new Human('jordan');
    let stub = sinon.stub(human, "hello");

    stub.returns("hello?");
    stub.withArgs("taro").returns("hello??");
    stub.withArgs("jiro").returns("hello???");

    assert.ok(human.hello() === "hello?");
    assert.ok(human.hello("taro") === "hello??");
    assert.ok(human.hello("jiro") === "hello???");
    human.hello.restore();
  });

  it('mock', () => {
    let human = new Human('kobe');
    let mock = sinon.mock(human);
    mock.expects("hello").twice();
    human.hello("taro");
    human.hello("jiro");
    assert.ok(mock.verify())
  });

  it("fake server", function(){
    let server = sinon.fakeServer.create();
    server.respondWith("GET", "./resouces/test1.json", 
      [200, {"Content-Type":"application/json"}, 
        '[{"id":12, "comment":"Hey there"}]']);
     
    let spy = sinon.spy();
    $.getJSON("./resouces/test1.json", spy);
    server.respond();
     
    assert.ok(spy.calledWith([{id:12, comment:"Hey there"}]));
     
    server.restore();
  });
});