Tuesday, July 1, 2014

Testing backbone application using jasmine with Grunt and requirejs

Yeoman backbone generatorがデフォルトでインストールするテストフレームワークはmocha, chaiの組み合わせ. これをJasmine2に切り替える方法について.
分かってしまえばなんてこたないんだけど、初見ではとても苦労した

前提

  • Yeoman backbone generatorでアプリケーションのひな形を作成
    • coffee script, requirejs, bootstrap 全部選択
  • API生成時に全てのファイルがtest/ディレクトリ下に配置されることに違和感を感じたため、specディレクトリを除いて一つ上のディレクトリに移動させている

必要な追加npmパッケージ

  • grunt-contrib-jasmine
  • grunt-template-jasmine-requirejs
それぞれローカルで入れる.
yukaary$ npm install grunt-contrib-jasmine --save-dev
yukaary$ npm install grunt-template-jasmine-requirejs --save-dev

Gruntfileの編集

初見で一番はまるところだと思う. デフォルトではmochaが使用される設定になっているところをjasmineに置き換える.
Gruntfileの関連箇所抜粋.
jasmine: {
    all: {
        # テスト対象(javascript)の場所を指定
        src: '.tmp/scripts/{,*/}*.js',
        options: {
            # テスト完了後もテストランナー(_SpecRunner.html)を残す
            keepRunner: true,
            # テストコードの場所を指定
            specs: '.tmp/spec/*.js',
            # grunt x jasmine x requirejsのテンプレートを使う.
            template: require('grunt-template-jasmine-requirejs'),
            templateOptions: {
                # require.config(...)が実装されているファイルを指定.
                requireConfigFile: '.tmp/scripts/main.js',
                requireConfig: {
                    # テスト時のルートディレクトリ.
                    baseUrl: '.tmp/scripts',
                    # テスト時に必要なライブラリ
                    paths: {
                        "jquery": "../../bower_components/jquery/dist/jquery",
                        "backbone": "../../bower_components/backbone/backbone",
                        "underscore": "../../bower_components/lodash/dist/lodash",
                        "bootstrap": "../../bower_components/sass-bootstrap/dist/js/bootstrap"
                    }
                }
            }
        }
    }
},
結構長い. これでも短くなるよう頑張ったんだけど…
Coffee Scriptを使用する設定でYeomanが生成するGruntfileは中間javascriptコードを.tmpディレクトリに配置するようになっている. 最終目標はdistディレクトリみたいだけど、ここのjavascriptは圧縮された状態なのでちょっと読めない. といった事情から.tmp下のjavascriptコードをテスト対象にする.
面倒なのはrequire.jsで、テスト実行時にこいつが依存する他のjavascriptを解決できるようにしてあげないといけない. baseUrlを再設定しているのはこのためで,テスト実行時の起点をCoffee Scriptコードで言うところのapp/scriptsにしてあげる事で大体のパス問題は解消する.
あとはbackbone等のサードライブラリのパス指定. これらを一時的な.tmpディレクトリ下に配置するのに違和感があったので多少面倒だけどrequireConfig;の中で再設定している. .tmp/scriptをカレントディレクトリと見て、2つ上にあるbower_componentsディレクトリを参照させている.

その他.

grunt-template-jasmine-requirejsはGruntタスクを実装していない?のでテスト実行時に毎回警告がでる.
こんなの.
>> Local Npm module "grunt-template-jasmine-requirejs" not found. Is it installed?
気になるようであればGruntfileの先頭でタスクをロードしているところを以下のように書き換えればでなくなる. やらないほうがいいかも.
//require('load-grunt-tasks')(grunt);
require('load-grunt-tasks')(grunt, {
    pattern: ['grunt-*', '!grunt-template-jasmine-requirejs']
});
testタスク実行時の処理の流れが書いてるところをmocha -> jasmineに変更しておく. 気まぐれで’open:test’も追加. できればliveloadにしたいな.
var testTasks = [
    'clean:server',
    'coffee',
    'createDefaultTemplate',
    'jst',
    'compass',
    'connect:test',
    'jasmine',
    'open:test'
];

テスト

上記のようにGruntfileを設定しておけばアプリケーションコードと同じようにCoffee Scriptでテストを書ける. Backbone本体、自作Backboneモデル双方がロードされていることを確認するために簡単なテストコードを書いた.


test/spec/test.coffee:
define [
  'underscore'
  'backbone'
  'models/recipe'
], (_, Backbone, RecipeModel) ->

  describe "Yukaary's 1st test", ->
    it "Maki san should dig tunnel.", ->
      expect(true).toBe(true);

    it "Zunko san shoud have zunda mochi.", ->
      expect(true).toBe(true);

  describe "Yukaary 1st backbone model", ->

    recipe = null

    beforeEach ->
      recipe = new RecipeModel

    afterEach ->
      recipe.destroy
      recipe = null

    it "depended components are loaded.", ->
      model = new Backbone.Model
      expect(model).toBeDefined()
      expect(recipe).toBeDefined()
細かいけどdefineにしとかないとテスト結果が出ない.

実行してみる.

yukaary$ grunt test
Running "test" task

Running "clean:server" (clean) task
Cleaning .tmp...OK

Running "coffee:dist" (coffee) task

Running "coffee:test" (coffee) task

Running "createDefaultTemplate" task

Running "jst:compile" (jst) task
File ".tmp/scripts/templates.js" created.

Running "compass:dist" (compass) task
directory .tmp/styles/ 
   create .tmp/styles/main.css (3.27s)
Compilation took 3.279s

Running "compass:server" (compass) task
unchanged app/styles/main.scss
Compilation took 0.357s

Running "connect:test" (connect) task
Started connect web server on http://localhost:9001

Running "jasmine:all" (jasmine) task
Testing jasmine specs via PhantomJS

 Yukaary's 1st test
   ✓ Maki san should dig tunnel.
   ✓ Zunko san shoud have zunda mochi.
 Yukaary 1st backbone model
   ✓ depended components are loaded.

3 specs in 0.007s.
>> 0 failures

Running "open:test" (open) task

Done, without errors.


Execution Time (2014-07-01 12:06:47 UTC)
loading tasks    1.7s  ▇▇▇▇▇▇▇▇ 18%
coffee:dist     136ms  ▇ 1%
compass:dist     4.1s  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 43%
compass:server  736ms  ▇▇▇▇ 8%
jasmine:all      2.5s  ▇▇▇▇▇▇▇▇▇▇▇▇ 26%
open:test       204ms  ▇ 2%
Total 9.5s
やったぜ.

今後

  • sinon.jsを使ってVIEWのテストができることを確認したい
  • liveload機能をつけたい
  • これを使ってカバレッジの計測をやる
  • そもそもの話、Gruntはもうやだ. 複雑すぎると思う.
    • grunt alternativeでgoogle検索したら先頭にgulpがひっかかったでござる.

1 comment:

  1. To start with, let me tell you, just what initiated as a efficient ruse turned out to be one of the better assets We stated in a long time. Every this usual buddies ended up being wondering everyone a lot more coppied or maybe stole keep an eye on, for the reason that everyone believes ways loving he could be from it. While i explained to these folks it's a watch, they will possibly not believe that the item. Not to mention regulations performed devices for example. He or she had been hot http://www.gavinwatches.co.uk/cartier-roadster-replica-uk.html, all the males mocking the dog for spending a lot of money for a factor that My partner and i sole settled one or two number of $. The moment this idiotic poker fun at visited a conclusion, most of us jeered it all shut off and even put a lot of our designer watches one alongside other, as a way to assess these folks. To begin with, you shuffled these people along with put them on a fabulous table. Without a doubt, it again had a while to be able to guess them mistaken. These folks were indistinguishable! Following a more examination, most people discovered several variance approximately my own authentic sit back and watch, however is not in any poor means, i must own up. Naturally for the reason that classy since she's, perhaps Charles congratulated us just for my best obtain, saying that if she or he suspected from this, although have inked like other people. Thinking that originates from a person intended for whom bucks isn't item. Which means rely on everyone to look at suggest this particular, investing in a enjoy surpasses paying out an income in the honest document.

    ReplyDelete