最近ハマっているcoffeescriptを使って説明します。
非同期な関数
google maps apiにはGeocoderなど、座標から地名を取得するような関数でサーバからの応答を待つ非同期関数が存在する。例えば下記のgeocode()関数が非同期な関数である。
geocode.coffee
class @Geocoder
constructor: ->
@geocoder = new google.maps.Geocoder()
@results
getPlaceName: (point) ->
request = {
language : "en"
latLng : point
}
geocoder.geocode(
request
(results, status) =>
# ここがサーバからの応答があってから実行されるcallback
@results = results
上記のcallback関数の実行後のテストをjsTestDriverを使って行いたい場合どうすればいいか?
sinon.jsを使って、擬似サーバによりテストを行う方法もあるが、今回の場合googleの応答結果を使ってテストしたいのでやり方を考えてみた。
jQuery Deferredを利用する
最初にsetTimeoutで少し待ってからテストを行えばいいと考えていたが、その方法ではうまく行かなかった。うまく行ったのは、AsyncTestCaseとjQuery Deferredを用いてテストする方法。
AsyncTestCaseについては先日の投稿にも書いた通りである。
また、jQuery Deferredについては下記を参考にした。
GeocoderクラスをDeferredを使って書き換える
というわけで、最初に書いたクラスをDeferredを用いて書き換えてみる。
geocode.coffee
class @Geocoder
constructor: ->
@geocoder = new google.maps.Geocoder()
@results
getPlaceName: (point) ->
defer = new $.Deferred() #追加
request = {
language : "en"
latLng : point
}
geocoder.geocode(
request
(results, status) =>
# ここがサーバからの応答があってから実行されるcallback
@results = results
defer.resolve() #追加
return defer.promise() #追加
テストケースを書いてみる
geocode_test.coffee
AsyncTestCase "Geocoder Test",
setUp: (queue)->
queue.call(
"prepare google map"
(callbacks) ->
onReadyGoogleMap = callbacks.add(
=>
@geocoder = new Geocoder()
)
$.when(
loadGoogleMaps(3, null, "en", false)
)
.done(
->
onReadyGoogleMap()
)
)
"test getPlaceName": (queue) ->
queue.call(
"wait function callback"
(callbacks) ->
success = callbacks.add(
=>
assertNotEquals(0, @geocoder.results.length) #ここにテストケースを書く
)
$.when(
@geocoder.getPlaceName(new google.maps.LatLng(37.4815, -122.2287))
)
.done(
->
success()
)
)
- setUp部分は、上にも書いたが先日書いた投稿の通り。こうしないとgoogleのapiのテストができない。
- "test getPlaceName"のテスト部分も、google apiのロードとやっていることは同じ。
- callbacks.addでcallback実行後のテストケースを予め登録しておく。こうしておくと、success()が実行されるまで、次のテストの実行を待機するようになる。
- getPlaceName()をjQuery deferred.promise()を返すように書き換えたので、$.whenで待つようにすることができる。
- geocode()のcallback内でdeferred.resolve()が実行されると、上記テストケースの.done()が実行される。
- success()のテストが実行される。