Blog
HTML5資料室 » Sinon.JS

Sinon.JS

Last modified by mtakeuchi on 2013/11/29, 15:36

 加筆中

Sinon.JSとは

テスト対象が依存しているモジュールやリソースの代役を務めてくれるライブラリです。
Sinon.JSは大きくわけて以下のAPIを持っています。

  • Spy
  • Stub
  • Mock
  • Fake timer
  • Fake XmlHttpRequest
  • Fake server
  • Assertion
  • Matcher
  • Sandbox
  • Utility

なお、Sinonは「シノン」と読むそうで、トロイ戦争で活躍したスパイの名前が由来とのこと。

使用方法

Spy

Spyはあるメソッドの代替として動作し、

  • 引数に何が渡されたか、
  • どのような戻り値を返したか、
  • 自身が何回呼び出されたか

等、実行結果に関する詳細な情報を持ちます。

API

var spy = sinon.spy()

var spy = sinon.spy();

function now(fn) {
  fn(+new Date());
}

now(spy);

// spyオブジェクトが実行されたか
console.log(spy.called); // true
// spyオブジェクトが実行された回数
console.log(spy.callCount); // 1
// spyオブジェクトに渡された値
console.log(spy.args[0]); // [1378948520055] (現在時刻のミリ秒を持つ配列)

var spy = sinon.spy(Function testFunc)

function getRgb(name) {
 var code = null;

 switch (name) {
 case 'red':
    code = '#f00';
   break;
 case 'green':
    code = '#080';
   break;
 case'yellow':
    code = '#ff0';
   break;
 case 'white':
    code = '#fff';
   break;
  }

 return code;
}

var spy = sinon.spy(getRgb);

spy('red');

console.log(spy.called);        // true
console.log(spy.returnValues);  // ['#ff0']
console.log(spy.callCount);     // 1

spy.reset();

var spy = sinon.spy(Object obj, String methodName)

var obj = {
  twice: function(num) {
   return num * 2;
  },
  half: function(num) {
   return num / 2;
  }
};

var spy = sinon.spy(obj, 'twice');

spy(10);

console.log(spy.called);        // true
console.log(spy.returnValues);  // [20]
console.log(spy.callCount);     // 1

その他のAPI

名前 戻り値説明
callCountNumber実行された回数
calledBoolean実行されたか
calledOnceBoolean1回実行されたか
calledTwiceBoolean2回実行されたか
calledThriceBoolean3回実行されたか
firstCallObjectt(実行結果の情報)1回目に実行されたときの結果情報を取得する
secondCallObjectt(実行結果の情報)2回目に実行されたときの結果情報を取得する
thirdCallObjectt(実行結果の情報)3回目に実行されたときの結果情報を取得する
lastCallObjectt(実行結果の情報)最後に実行されたときの結果情報を取得する
calledBefore(anotherSpy)Boolean指定したSpyオブジェクトよりも前に自身が実行されたか
calledAfter(anotherSpy)Boolean指定したSpyオブジェクトよりも後に自身が実行されたか
calledOn(Object thisValue)Boolean指定したオブジェクトが、自身のコンテキストと同じか
alwaysCalledOn(ObjectthisValue)Boolean指定したオブジェクトが、今まで実行した全てのメソッドのコンテキストと同じか
calledWith(arg1, arg2, ...)Booleanメソッド実行時の引数が、指定した値と完全(厳密等価比較)に一致しているか
alwaysCalledWith(arg1, arg2, ...)Boolean全ての実行において、メソッド実行時の引数が指定した値と同じか
calledWithExactly(arg1, arg2, ...)Booleanメソッド実行時の引数の内容と長さが指定した値と同じか
alwaysCalledWithExactly(arg1, arg2, ...)Boolean全ての実行において、メソッド実行時の引数の内容と長さが指定した値と同じか
calledWithMatch(arg1, arg2, ...)Booleanメソッド実行時の引数のそれぞれの値が、指定した値と完全に一致しているか
alwaysCalledWithMatch(arg1, arg2, ...)Boolean全ての実行において、メソッド実行時の引数の値が、指定した値と完全に一致しているか
calledWithNew()Booleanスパイでnew演算子が呼ばれたか
neverCalledWith(arg1, arg2, ...)Booleanこのメソッドに指定したいずれかの引数と、テストメソッド実行時の引数が同じでないこと
neverCalledWithMatch(arg1, arg2, ...)Booleanこのメソッドに指定した全ての引数と、テストメソッド実行時の引数が同じでないこと
threw()Boolean一回以上例外をスローしたか
threw("TypeError")Boolean指定した型のエラーを1回以上スローしたか
threw(obj)Boolean指定したエラーオブジェクトで1回以上スローしたか
alwaysThrew()Boolean全ての実行に置いて、例外をスローしたか
alwaysThrew("TypeError")Boolean全ての実行に置いて、指定した型のエラーをスローしたか
returned(Objet anyValue)Boolean引数に指定した値が、Spyメソッドが直前で返した値と一致するか
alwaysReturned(Objet anyValue)Booleanテスト対象のメソッドが常に引数で指定した値を返しているか
spy.getCall(Number index)Objectt(実行結果の情報)X回目の結果情報を取得する
thisValuesArray[Object, ...]Spyがテストしたメソッドのコンテキスト(thisの値)
argsArray[Object, ...]Spyオブジェクトに渡されたパラメータの値
exceptionsArray[Object, ...]Spy化したメソッドでスローされたエラーオブジェクトを持つ配列
returnValuesArray[Object, ...]Spy化したメソッドが返した値
reset()VoidSpy化したメソッドを元の状態に戻す
printf(String formatString, [arg1, arg2, ...])String指定したフォーマットで文字列を出力します

Stub

Stubは、ある機能をテストするために必要な別機能の代替として動作します。
Spyは主に実行結果に関する情報のみを持っていますが、StubはSpyの機能に加えてある条件の場合は例外をスローする、この引数の場合はこの値を返す、といったように振る舞いを変更する機能を持っています。

API

var stub = sinon.stub()

anonymousメソッドのスタブを生成します

var stub = sinon.stub();
stub.withArgs(42).returns(1);
stub.withArgs(1).throws('HogeError', '例外発生!');

console.log(stub()); // undefined
console.log(stub(42)); // 1
try {
  stub(1); // HogeErrorがスローされる
} catch(e) {
  console.log(e.message); // 例外発生!
}

var stub = sinon.stub(Object obj, String methodName)

第一引数のオブジェクトが持つ、第二引数に指定された名前のメソッドを、スタブに差し替えます。
もとのメソッドに戻す場合は、obj[methodName].restore()またはstub.restore()を実行します。

function ModuleA() {
 this.ar = [];
};

ModuleA.prototype.calc = function(data) {
 this.ar.push(data.calculate());
};

ModuleA.prototype.result = function(data) {
 return this.ar.join(',');
};

function TestData(num) {
 this.num = num;
}

TestData.prototype.calculate = function() {
 // 未実装 Stubで代替を用意する
};

var testData = new TestData(10);
var modA = new ModuleA();

var stub = sinon.stub(testData, 'calculate');

modA.calc(testData);

console.log(testData.calculate.returnValues[0] === modA.ar[0]); // true

testData.calculate.restore(); // スタブ機能を削除する

var stub = sinon.stub(Object obj, String methodName, Function func)

第一引数のオブジェクトが持つ、第二引数に指定された名前のメソッドを、第三引数のメソッドに差し替えます。
もとのメソッドに戻す場合は、obj[methodName].restore()またはstub.restore()を実行します。

function ModuleA() {
 this.ar = [];
};

ModuleA.prototype.calc = function(data) {
 this.ar.push(data.calculate());
};

ModuleA.prototype.result = function(data) {
 return this.ar.join(',');
};

function TestData(num) {
 this.num = num;
}

TestData.prototype.calculate = function() {
 // 未実装 Stubで代替を用意する
};

var testData = new TestData(10);
var modA = new ModuleA();

var stub = sinon.stub(testData, 'calculate', function() {
 return parseInt(Math.random() * 10);
});

modA.calc(testData);

console.log(testData.calculate.returnValues[0] === modA.ar[0]); // true
stub.restore(); // スタブ機能を削除する (stub.calculate.restore()でも可)

var stub = sinon.stub(obj)

指定したオブジェクトにスタブ機能を付与します。
もとのオブジェクトの状態に戻す場合は、obj[メソッド名].restore()またはstub.restore()を実行します。

function ModuleA() {
this.ar = [];
};

ModuleA.prototype.calc = function(data) {
 this.ar.push(data.calculate());
};

ModuleA.prototype.result = function(data) {
 return this.ar.join(',');
};

function TestData(num) {
 this.num = num;
}

TestData.prototype.calculate = function() {
// 未実装 Stubで代替を用意する
};

var testData = new TestData(10);
var modA = new ModuleA();

var stub = sinon.stub(testData);

modA.calc(stub);

console.log(stub.calculate.returnValues[0] === modA.ar[0]); // true

stub.restore(); // スタブ機能を削除する (stub.calculate.restore()でも可)

その他のAPI

名前 戻り値説明
stub.withArgs(arg1, arg2, ...)Stub引数によってStubの振る舞いを変えたい場合にその引数を設定します
stub.returns(Object returnValue)StubStubが返すべき値を設定します
stub.returnsArg(Number index)Stubこのメソッドでインデックスを設定後、引数を指定してStubを実行すると、Stubはこの引数のindex番目を戻り値として返します
stub.throws()StubStubが例外をスローするよう設定します
stub.throws(String ErrorType)Stub引数に指定した型のエラーをスローするよう設定します
stub.throws(Object throwObj)Stub引数に指定したエラーオブジェクトをスローするよう設定します
stub.callsArg(Number index)Stubこのメソッドでインデックスを設定後、引数を指定してStubを実行すると、Stubはこの引数のindex番目をコールバック関数として実行します
stub.callsArgOn(Number index, Object context)Stubこのメソッドでインデックスを設定後、引数を指定してStubを実行すると、Stubはcontextに指定したオブジェクトをthisに設定して、Stubに指定した引数のindex番目をコールバック関数として実行します。
stub.callsArgWith(Number index, arg1, arg2, ...)Stubこのメソッドでインデックスを設定後、引数を指定してStubを実行すると、StubはcallsArgWith()の第二引数以降の値を引数としてStubに指定した引数のindex番目をコールバック関数として実行します
stub.callsArgOnWith(Number index, Object context, arg1, arg2, ...)Stubこのメソッドでインデックスを設定後、引数を指定してStubを実行すると、StubはcallsArgOnWith()の第二引数に指定したオブジェクトをコンテキスト(this)に、第三引数以降の値を引数として、Stubに指定した引数のindex番目をコールバック関数として実行します
stub.yields(arg1, arg2, ...)StubcallsArg()に似ています。異なる点はユーザがコールバックとして実行してほしい引数のインデックス番号を指定しないところです。Stubに指定した引数の中から最初に見つかった関数のみを実行します。
stub.yieldsOn(context, arg1, arg2, ...)StubcallsArgOn()に似ています。異なる点はユーザがコールバックとして実行してほしい引数のインデックス番号を指定しないところです。Stubに指定した引数の中から最初に見つかった関数のみを実行します。
stub.yieldsTo(property, arg1, arg2, ...)Stubyields()に似ています。異なる点は第一引数にオブジェクトのプロパティ名を指定するところです。Stubの引数にはオブジェクトを指定します。指定したオブジェクトからpropertyに指定したプロパティの値(コールバック)を実行します。
stub.yieldsToOn(property, context, arg1, arg2, ...)Stubコールバックのコンテキストを第二引数に指定する以外はyieldsTo()と同じです。
stub.yield(arg1, arg2, ...)Stubこのメソッドに指定された引数Stubの引数に指定されたコールバックを全て実行します。
stub.yieldTo(Function callback, arg1, arg2, ...)Stub
stub.callArg(argNum)インデックス番号を指定してStubの引数に指定したコールバックを実行します
stub.callArgWith(argNum, args1, arg2, ...)Stub Stubの引数に指定したindex番目のコールバックを実行します。実行されたコールバックの引数にはcallArgWith()の第二引数以降に指定した値が渡されます。
stub.callsArgAsync(Number index)Stubの引数に指定したindex番目のコールバックを非同期で実行します。
stub.callsArgOnAsync(Number index, Object context)Stubcontextに指定したオブジェクトをthisに設定して、Stubの引数に指定したindex番目のコールバックを非同期で実行します。
stub.callsArgWithAsync(Number index, arg1, arg2, ...)Stubインデックス番号を指定してStubの引数に指定したコールバックを非同期実行します。実行されたコールバックの引数にはcallsArgWithAsync()の第二引数以降に指定した値が渡されます。
stub.callsArgOnWithAsync(Number index, Object context, arg1, arg2, ...)Stub非同期でcallsArgOnWith()を実行します
stub.yieldsAsync(Arrary args)Stub非同期でyields()を実行します
stub.yieldsOnAsync(Object context, Array args)Stub非同期でyieldsOn()を実行します
stub.yieldsToAsync(String property, Array args)Stub非同期でyieldsTo()を実行します
stub.yieldsToOnAsync(String property, Object context, Array args)Stub非同期でyieldsToOn()を実行します

Mock

Mockは、Stubの機能に加えて設定した期待値どおりにメソッドが実行されたかを検証する機能を持っています。

API

var mock = sinon.mock(obj)

引数に指定したオブジェクトからMockオブジェクトを生成します。

var expectation = mock.expects("method")

引数に指定したメソッド名を持つメソッドに、MockのExpectation(検証機能)を付与します。
メソッドからExpectationを除去する場合は、mock.restore()を実行します。

var mock = sinon.mock(jQuery);

mock.expects("ajax").atLeast(2).atMost(5);
mock.verify();
mock.restore();

mock.verify()

Expectationに指定した条件通りにメソッドが実行されたかを検証します。
実行されていないと例外をスローします。

var myAPI = { func1: function () {} };

var mock = sinon.mock(myAPI);
mock.expects("func1").twice(); // メソッドfunc1が2回実行されることを期待値に設定

myAPI.func1();

mock.verify(); // func1が2回実行されたか検証する

上記の場合、mock.verify()を実行すると

   Uncaught ExpectationError: Expected func1([...]) twice (called once) 

例外がスローされて、期待値と実行結果が一致していないことを知らせます。

Expectations

Mock.verify()での検証に必要な期待値を設定できます。
Mock.expects()を実行すると、Expectationオブジェクトを取得できます。

API

名前 戻り値説明
expectation.atLeast(Number number)Expectation呼び出される最小回数を期待値として設定します
expectation.atMost(Number number)呼び出される最大回数を期待値として設定します
expectation.never()呼び出されないことを期待値として設定します
expectation.once()1度のみ呼び出されることを期待値として設定します
expectation.twice()2度呼び出されることを期待値として設定します
expectation.thrice()3度呼び出されることを期待値として設定します
expectation.exactly(Number number)呼び出される回数を期待値として設定します
expectation.withArgs(arg1, arg2, ...)指定した引数で呼び出されることを期待として設定します
expectation.withExactArgs(arg1, arg2, ...)指定した引数以外で呼び出されることを期待値として設定します
expectation.on(obj)実行したメソッドのコンテキスト(this)が引数で指定したオブジェクトであることを期待値として設定します

Fake Timer

Fake TimerはsetTimeout()、clearTimeout()、setInterval()、clearInterval()とDateオブジェクトの時間を操作することができます。

API

var clock = sinon.useFakeTimers()

現在時刻を開始時間とする、Clockオブジェクトを生成します。
このメソッドを実行すると、setTimeout()、clearTimeout()、setInterval()、clearInterval()とDateオブジェクトはSinonによって書き換えられます。
これを、元に戻すにはclock.restore()または、[setTimeout|clearTimeout|setInterval|clearInterval].clock.restore()を実行します。

var clock = sinon.useFakeTimers(); // FakeTimerオブジェクトを生成する

setTimeout(function() {
  alert('Hello!'); // tick()で2000ms経過したものとして即座にアラートが実行される
}, 2000);

clock.tick(2000); // 2000ms経過させる

var clock = sinon.useFakeTimers(Number millis)

引数に指定された時刻を開始時間とする、Clockオブジェクトを生成します。

var clock = sinon.useFakeTimers([Number now, ] String prop1, String prop2, ...)

引数に指定された時刻を開始時間とする、Clockオブジェクトを生成します。
第二引数以降には、操作したいメソッド名(setTimeout、clearTimeout、setInterval、clearInterval)を指定します。

clock.tick(Number ms);

引数に指定した時間(ミリ秒)分、時間を経過させます。
経過したことにより影響を受けたタイマーは全て実行されます。

Fake XMLHttpRequest

XMLHttpRequest(XHR)を模倣した、動作を自由に操作するためのインターフェースを提供します。
通常はこのAPIを単体で使用することなく、後述のFake Serverとセットで使用します。

IEでこのAPIを使用する場合は、sinon.js(最新版はsinon-1.7.3.js)のあとにsinon-ie.js(最新版はsinon-ie-1.7.3.js)を読み込む必要があります。

API

var xhr = sinon.useFakeXMLHttpRequest()

ネイティブのXHRを書き換えて、XHRを模倣するFakeXMLHttpRequestオブジェクトを生成します。
元のXHRに戻したい場合は、xhr.restore()を実行します。

xhr.onCreate = function (FakeXMLHttpRequest xhr) {}

$.ajax()等でXHRが生成されたタイミングで、onCreateプロパティに設定したコールバックメソッドが実行されます。

FakeXMLHttpRequest

useFakeXMLHttpRequest()が返す値とonCreateに指定したコールバック関数が返す値は両方ともFakeXMLHttpRequestですが、持っているプロパティが異なるため、使用時する際には注意が必要です。

FakeXMLHttpRequest(useFakeXMLHttpRequest()が返すオブジェクト)
名前 戻り値説明
restore()VoidFakeXMLHttpRequestの機能を除去して、ネイティブのXHRに戻します。
useFiltersBooleanaddFilter()を実行するかのフラグを設定します。デフォルトはfalseです。
addFilter(Function(String method, String url, Boolean async, String username, String password))Void xhr.open()が実行される直前に実行されるコールバックメソッドを追加します。
FakeXMLHttpRequest(onCreateのコールバック関数が返すオブジェクト)
名前 戻り値説明
urlStringURL
methodStringメソッド名
requestHeadersObjectリクエストヘッダの全ての情報
requestBodyStringリクエストボディ
statusNumberステータス
statusTextStringステータス情報
asyncBoolean非同期通信であるかのフラグ
usernameStringユーザ名
passwordStringパスワード
getResponseHeader(String headerName)Stringレスポンスヘッダを取得します
getAllResponseHeaders()Array全てのヘッダ情報を取得します
setResponseHeaders(Object headerDef)Voidレスポンスヘッダを設定します
setResponseBody(String body)Voidレスポンスボディを設定します
setRequestHeader(String headerName, String value)Voidヘッダ名と値を指定してリクエストヘッダを設定します
respond(Number status, Object headerDef, String body)Voidステータス、レスポンスヘッダ、レスポンスボディを設定します

※実際の動作を確認したところ、FakeXHRにresponseXML/autoRespondAfter()/autoRespondが定義されていなかったため、API一覧から除外しています。

Fake Server

FakeXMLHttpRequestインスタンスを操作するための高レベルAPIです。

API

var server = sinon.fakeServer.create()

Fake Serverインスタンスを生成します。このAPIは内部でsinon.useFakeXMLHttpRequest()を実行します。
書き換えられたXHRを元に戻す場合は、server.restore()を実行して下さい。

var server = sinon.fakeServerWithClock.create()

タイマー(時刻)を詐称する機能を持つFake Serverインスタンスを生成します。
書き換えられたXHRを元に戻す場合は、server.restore()を実行して下さい。

server.respondWith(String|Array|Function response)

指定されたURLで実行されたAjaxに対するレスポンスを設定します。
デフォルトは

  • ステータスコード: 404
  • レスポンスヘッダ: {}
  • レスポンスボディ: ""

を返すよう設定されています。

このメソッドのパラメータには、以下の3通りの指定ができます。

  • レスポンスボディ文字列
  • ステータスコード、レスポンスヘッダ、レスポンスボディの順で値を持つ配列
  • 関数

server.respondWith(String url, String|Array|Function response)

第一引数のURLでAjaxで呼び出された場合に返すレスポンスを設定します。

server.respondWith(String method, String url, String|Array|Function response)

第一引数のメソッド(GET,POST,PUT,DELETE)と第二引数のURLでAjaxで呼び出された場合に返すレスポンスを設定します。

server.respondWith(RegExp urlRegExp, String|Array|Function response)

第一引数の正規表現に一致するURLでAjaxで呼び出された場合に返すレスポンスを設定します。

server.respondWith(String method, RegExp urlRegExp, String|Array|Function response)

第一引数のメソッド(GET,POST,PUT,DELETE)と、第二引数の正規表現に一致するURLでAjaxで呼び出された場合に返すレスポンスを設定します。

server.respond()

respondWith()で設定した条件に一致する呼び出しに対して、非同期でレスポンスを返します。
そのため、respond()を実行するよりも前にrespondWith()に値を設定する必要があります。

server.autoRespond

trueを設定した場合、respond()を実行しなくても自動でrespondWith()の条件に一致する呼び出しに対してレスポンスを返します。

server.autoRespondAfter

呼び出しが行われてから何ms後にレスポンスを返すか時間(ミリ秒)を指定します。
server.autoRespondがtrueの場合のみ有効になります。

server.fakeHTTPMethods

trueを設定した場合、server.getHTTPMethod()の引数に指定されたリクエストボディから_methodを探してそのパラメータに指定されているメソッドが実際の通信で使用するメソッドとして判定します。

server.getHTTPMethod(Object request)

引数に指定されたリクエストオブジェクトから、HTTPメソッドを決定するために使用される内部関数。

server.restore()

sinon.fakeServer.create() または sinon.fakeServerWithClock.create() の実行によって書き換えられたXHRクラスを、元の状態(ネイティブ)に戻します。

Assertion

Assertionは、SpyとStubが持つ情報を検証するための機能を提供します。

以下のコードは、spyオブジェクトが1回実行されたかをアサートしています。

var spy = sinon.spy();

function now(fn) {
  fn(+new Date());
}

now(spy);

sinon.assert.calledOnce(spy);

アサートの結果に誤りがある場合は例外が発生します。
例えば、sinon.assert.calledOnce()の場合は、デフォルトで以下のメッセージが表示されます。

  Uncaught AssertError: expected spy to be called once but was called twice

API

名前 戻り値説明
sinon.assert.fail(message)void引数のメッセージを保持する、sinon.assert.failExceptionで指定されたエラークラスをスローします
sinon.assert.failExceptionAssersion APIがスローするデフォルトのエラークラス(デフォルトはAssertError)
sinon.assert.pass(assertion)アサートが通過するごとに実行されるメソッドを定義します
sinon.assert.notCalled(spy)引数のSpyが一度も呼び出されていないかチェックします
sinon.assert.called(spy)引数のSpyが一度も呼び出されていないか検証します
sinon.assert.calledOnce(spy)引数のSpyが1度実行されたかを検証します
sinon.assert.calledTwice()引数のSpyが2度実行されたかを検証します
sinon.assert.calledThrice()引数のSpyが3度実行されたかを検証します
sinon.assert.callCount(spy, num)引数のSpyが第二引数numの回数分実行されたかを検証します
sinon.assert.callOrder(spy1, spy2, ...)引数で指定した順番でSpyが実行されたかを検証します
sinon.assert.calledOn(spy, obj)Spyが実行されたときのコンテキスト(this)が、第二引数のobjであるかを検証します
sinon.assert.alwaysCalledOn(spy, obj)全ての実行において、実行されたときのコンテキスト(this)が第二引数のobjであるかを検証します
sinon.assert.calledWith(spy, arg1, arg2, ...)第二引数以降に指定された値と同じ引数でSpyが実行されたか(部分一致)を検証します
sinon.assert.alwaysCalledWith(spy, arg1, arg2, ...)全ての実行において、第二引数以降に指定された値と同じ引数でSpyが実行されたか(部分一致)を検証します
sinon.assert.neverCalledWith(spy, arg1, arg2, ...)全ての実行において、第二引数以降に指定された値と異なる引数でSpyが実行されたかを検証します
sinon.assert.calledWithExactly(spy, arg1, arg2, ...)第二引数以降に指定された値と同じ引数でSpyが実行されたか(完全一致)を検証します
sinon.assert.alwaysCalledWithExactly(spy, arg1, arg2, ...)全ての実行において、第二引数以降に指定された値と同じ引数でSpyが実行されたか(完全一致)を検証します
sinon.assert.calledWithMatch(spy, arg1, arg2, ...)引数ごとにsinon.match()でマッチングを行います。このメソッドは sinon.assert.calledWith(spy, sinon.match(arg1), sinon.match(arg2), ...) と同義です
sinon.assert.alwaysCalledWithMatch(spy, arg1, arg2, ...)全ての実行において、引数ごとにsinon.match()でマッチングを行います。このメソッドは sinon.assert.alwaysCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...) と同義です
sinon.assert.neverCalledWithMatch(spy, arg1, arg2, ...)引数ごとにsinon.match()でマッチングを行い、全て一致しないことを検証します。
sinon.assert.threw(spy, exception)spyの実行で第二引数のexceptionと同じ型の例外が発生したかを検証します
sinon.assert.alwaysThrew(spy, exception)全てのspyの実行で、第二引数のexceptionと同じ型の例外が発生したかを検証します
sinon.assert.expose(object, options)第一引数objectに指定したオブジェクトに、Assert APIを公開します。第二引数のoptionsには2つのプロパティを指定できます。1つ目はprefixで、公開されるアサーションメソッドの接頭辞に付与したい文字列をこのプロパティに指定します。2つ目はincludeFailで、trueをこのプロパティに指定すると、failfailExceptionも一緒に公開します

sinon.assert.calledWith()とsinon.assert.calledWithExactly()の違い

calledWith()は、Spyを実行したときに指定された引数と部分一致すればアサートが通りますが、
calledWithExactly()の場合は完全に引数が一致している必要があります。

以下のコードは、calledWith()の実行により部分一致でアサートがパスすることを確認できます

var spy = sinon.spy();

spy(10, 11, 12, 13);

sinon.assert.calledWithExactly(spy, 10, 11, 12); // パスするので例外は発生しない

以下のコードは、calledWithExactly()の実行により完全一致でないとアサートがパスしないことを確認できます

var spy = sinon.spy();

spy(10, 11, 12, 13);

sinon.assert.calledWithExactly(spy, 10, 11, 12); // 第四引数の13が一致していないので、例外がスローされる

Matcher

Matcherはsinon.assertと同様に、spy.returned、spy.calledWithへの引数として渡すことができます。 Matcherは曖昧または厳密に判定をおこなうことができます。

以下のコードは、メソッドがどのような引数で実行されたかをMatcherを使用してアサートしています。(※1)

var book = {
  pages: 42,
  author: "cjno"
 };
var spy = sinon.spy();

 spy(book);

 sinon.assert.calledWith(spy, sinon.match({
  author: "cjno"
 }));

 sinon.assert.calledWith(spy, sinon.match.has("pages", 42));

calledWithでmatcherに指定した期待値とspyの結果が異なる場合、以下のような例外が発生します。
以下の例外は、sinon.match.has()でpagesの期待値を42から41に変更した場合の結果です。

Uncaught AssertError: expected spy to be called with arguments has("pages", 41)
    spy({ author: "cjno", pages: 42 }) 

API

名前 戻り値説明
sinon.match(number)Matcher数値を等価比較するMatcherを生成します
sinon.match(string)文字列を部分一致で比較するMatcherを生成します
sinon.match(regexp)正規表現に一致するMatcherを生成します
        
sinon.match(object)オブジェクトの構造に部分的または完全に一致することを検証するMatcherを生成します。引数の値は比較するオブジェクトと部分または完全に同じプロパティを持っていることと、nullまたはundefinedではない必要があります
sinon.match(function)カスタムMatcherを生成します
sinon.match.any値が定義されていないことを検証するMatcherを生成します
sinon.match.defined値が定義されていることを検証するMatcherを生成します
sinon.match.truthy値がtrueであることを検証するMatcherを生成します。但し"1"、1とった値でもtrueと判定されるため注意
sinon.match.falsy値がfalseであることを検証するMatcherを生成します。但し""、0とった値でもfalseと判定されるため注意
sinon.match.bool値が真偽値(true/false)であることを検証するMatcherを生成します
sinon.match.number値が数値型であることを検証するMatcherを生成します
sinon.match.string値が文字列であることを検証するMatcherを生成します
sinon.match.object値がオブジェクトであることを検証するMatcherを生成します
sinon.match.func値がメソッドであることを検証するMatcherを生成します
sinon.match.array値が配列であることを検証するMatcherを生成します
sinon.match.regexp値が正規表現であることを検証するMatcherを生成します
sinon.match.date値が日付であることを検証するMatcherを生成します
sinon.match.same(ref)比較する値と引数の値を厳密比較で一致することを検証するMatcherを生成します
sinon.match.typeOf(type)比較する値が引数に指定した型であるかを検証するMatcherを生成します
sinon.match.instanceOf(type)比較する値が引数に指定した型のインスタンスであるかを検証するMatcherを生成します
sinon.match.has(property[, expectation])比較する値が指定したプロパティを定義しているかを検証するMatcherを生成します
sinon.match.hasOwn(property[, expectation])sinon.match.hasと検証内容は同じですが、プロパティが自分自身に定義がいる必要があり、継承されたプロパティは無視されます。

条件を組み合わせて使用する

全てのMatcherAPIはor()and()を実装しています。
この2つのメソッドを使用することで、複数の条件を指定したMatcherを作成することができます。

以下のコードは、※1のコードをand()を使用して書き換えたものです。

var book = {
  pages: 42,
  author: "cjno"
 };
var spy = sinon.spy();

 spy(book);

var combinationMatcher = sinon.match({author: "cjno"}).and(sinon.match.has("pages", 42));

 sinon.assert.calledWith(spy, combinationMatcher);

カスタムMatcherを作成する

sinon.match() にメソッドとエラーメッセージを指定することで、独自のMatcherを作成することができます。

以下のコードは、※1のコードをカスタムMatcherで書き換えたものです。

var book = {
  pages: 42,
  author: "cjno"
};
var spy = sinon.spy();

spy(book);

sinon.assert.calledWith(spy, sinon.match({
  author: "cjno"
}));

var customMatcher = sinon.match(function (value) {
    value.pages === 42 && value .author === "cjno"
}, "値が不正です");

sinon.assert.calledWith(spy, trueIsh);

Sandbox

Sandboxを使用すると、restoreとverifyの呼び出しが簡略化されます。
また、グローバルにアクセス可能なfakeXHR、fakeTimerやStubを使用している場合は、Sandboxを使用することでクリーンアップが容易になります。

API

var sandbox = sinon.sandbox.create()

Sandboxオブジェクトを生成します。

var sandbox = sinon.sandbox.create(config)

引数に指定した設定情報に従って、Sandboxオブジェクトを生成します。

デフォルトの設定値

sinon.defaultConfig = {
    injectInto: null,
    properties: ["spy", "stub", "mock", "clock", "server", "requests"],
    useFakeTimers: true,
    useFakeServer: true
}
各設定値の説明
プロパティ名説明
injectIntopropertiesで指定された機能を、このプロパティに指定したオブジェクトに公開します
propertiesどの機能をsandboxで有効にするか、機能を表す文字列(spy/stub/mock/clock/server/requests)を持つ配列で指定します。
useFakeTimerstrueを設定すると、clockというプロパティ名でFakeTimer APIを公開します。
useFakeServertrueを設定すると、serverとrequestsというプロパティ名でFakeServer APIを公開します

sandbox.spy()

sandbox.restore()で復元可能な、Spyオブジェクトを生成します

sandbox.stub()

sandbox.restore()で復元可能な、Stubオブジェクトを生成します

sandbox.mock()

sandbox.restore()で復元可能な、Mockオブジェクトを生成します

sandbox.useFakeTimers()

sandbox.restore()で復元可能な、Fake Timerオブジェオブジェクトを生成します

sandbox.useFakeXMLHttpRequest()

sandbox.restore()で復元可能な、FakeXHRオブジェクトを生成します

sandbox.useFakeServer()

sandbox.restore()で復元可能な、Fake Serverオブジェクトを生成します

sandbox.restore()

各APIを元の状態にもどします

Utility

Sinon.JSにはライブラリや内部で使用されているユーティリティがいくつか存在しますが、以下で説明されていないメソッドはパブリックなAPIではないため、将来変更される可能性があるため注意が必要です。

API

sinon.createStubInstance(Function constructor)

引数に指定したコンストラクタがprototypeに持つメソッドを全てStub化したオブジェクトを返します。
引数に指定したコンストラクタは実行されません。Stubの詳細についてはこちらを参照して下さい。

sinon.format(Object obj)

指定したオブジェクトの構造を文字列に表現します。

var obj = {
  inner1: {
    inner2: {
      func: function() {
        alert('hello!');
      },
      num1: 10,
      str1: 'aaa'
    }
  }
};

sinon.format(obj);

実行結果

{ inner1: { inner2: { func: function () {}, num1: 10, str1: "aaa" } } } 

sinon.log(String message)

デバッグに役立つ内部エラーを出力します。デフォルトは空のメソッドが設定されているので、必要に応じて設定を変更して下さい。

例.内部エラーをコンソールに出力する場合

sinon.log = function(message) {
  console.log(message);
};

Copyright (C) 2012-2017 NS Solutions Corporation, All Rights Reserved.