はじめに
$timeout
$timeout
は window.setTimeout をラップした angularJS のサービスで、次のように使う
it "$timeout は予約をキャンセルすることが出来る", ->
inject ["$timeout", ($timeout) ->
counter = 0
promise = $timeout (-> counter++), 1000 # 1 秒後にカウントアップ
$timeout.cancel promise # だが断る
$timeout.flush
expect(counter).toBe 0
]
spyOn
spyOn
はテストダブルのための jasmine の機能で、その関数が呼ばれたかどうかをチェックする
it "spyOn は関数が呼ばれたかどうかをテスト出来る", ->
hoge =
fuga: -> "fuga"
foo: -> fuga()
spyOn(hoge, "fuga").and.callThrough()
hoge.foo()
expect(hoge.fuga).toHaveBeenCalled()
$timeout を spyOn するには?
spyOn
はオブジェクトの要素となっている関数は spy することが出来るが、$timeout
みたいな、どこにも属していないような関数を spy することが出来ない。
失敗: 無理やり
it "別の Object の要素にした上でそいつを spy", ->
inject ["$timeout", ($timeout) ->
hoge =
$timeout: $timeout
spyOn(hoge, "$timeout").and.callThrough()
$timeout (-> ), 1000
expect(hoge.$timeout).not.toHaveBeenCalled()
expect(hoge.$timeout).not.toBe $timeout
]
→ spyOn した時点で、 $timeout
と hoge.$timeout
は別物
準成功: decorator + jasmine.createSpy を使用する
beforeEach ->
module ["$provide", ($provide) ->
$provide.decorator "$timeout", ($delegate) ->
return jasmine.createSpy $delegate
]
it "flush とか cancel が居なくなる", ->
inject ["$timeout", ($timeout) ->
counter = 0
$timeout (-> counter ++), 1000
expect($timeout).toHaveBeenCalled() # 成功
$timeout.flush() # 失敗。 undefined is not a function
expect(counter).toBe 1
]
jasmine.createSpy を呼ぶと、次のような関数が返る。
console.log($timeout.toString())
function () {
callTracker.track({
object: this,
args: Array.prototype.slice.apply(arguments)
});
return spyStrategy.exec.apply(this, arguments);
}
要は、$timeout は関数であって、 flush や cancel が使えなくなってしまう。
失敗: decorator + createSpyObj
createSpyObj なら、関数の代わりに Obj を生成してくれる。
beforeEach ->
module ["$provide", ($provide) ->
$provide.decorator "$timeout", ($delegate) ->
return jasmine.createSpyObj $delegate, Object.keys $delegate # 第2引数で渡した配列の各要素がオブジェクトの key になる
]
it "$timeout 自体は spy ではない"
inject ["$timeout", ($timeout) ->
$timeout (-> ), 1000
expect($timeout).toHaveBeenCalled() # Expected a spy, but got { うんたらかんたら
]
$timeout の各キーが spy になる模様
成功 decorator + 無理やり
beforeEach ->
module ["$provide", ($provide) ->
$provide.decorator "$timeout", ($delegate) ->
holder =
$timeout: $delegate
spyOn(holder, "$timeout").and.callThrough()
return holder.$timeout
]
it "スパッてる"
inject ["$timeout", ($timeout) ->
$timeout (-> ), 1000
expect($timeout).toHaveBeenCalled() # 成功
]
おまけ
需要ありそうなので helper 化した
spyDecorator = ($delegate) ->
holder = {$delegate}
spyOn(holder, "$delegate").and.callThrough()
return holder.$delegate