2013-02-15 2 views
14

私たちはEmber.jsを学んでいます。我々はすべての開発TDDを行い、Ember.jsも例外ではないようにしたい。テストベースのBackbone.jsアプリケーションを構築した経験がありますので、JasmineまたはMocha/Chaiを使用してフロントエンドコードをテストすることに精通しています。ember.jsでテストビューをユニット化する方法は?

ビューをテストする方法を理解するとき、ビューのテンプレートに#linkToステートメントがあるときに問題が発生しました。残念ながら、私たちは良いテストの例とプラクティスを見つけることができません。この要点は、emberアプリケーションを適切に単体テストする方法の答えを得ることです。

test for linkTo in Ember.js source codeを見ると、#linkToをサポートするemberアプリの完全な配線が含まれていることがわかりました。これは、テンプレートをテストするときにこの動作をスタブすることができないことを意味しますか?

テンプレートレンダリングを使用してemberビューのテストを作成するにはどうすればよいですか?

ここにはa gistがあり、テストに合格するテンプレートとテストに合格するテンプレートと失敗するテンプレートがあります。

view_spec.js.coffee

# This test is made with Mocha/Chai, 
# With the chai-jquery and chai-changes extensions 

describe 'TodoItemsView', -> 

    beforeEach -> 
    testSerializer = DS.JSONSerializer.create 
     primaryKey: -> 'id' 

    TestAdapter = DS.Adapter.extend 
     serializer: testSerializer 
    TestStore = DS.Store.extend 
     revision: 11 
     adapter: TestAdapter.create() 

    TodoItem = DS.Model.extend 
     title: DS.attr('string') 

    store = TestStore.create() 
    @todoItem = store.createRecord TodoItem 
     title: 'Do something' 

    @controller = Em.ArrayController.create 
     content: [] 

    @view = Em.View.create 
     templateName: 'working_template' 
     controller: @controller 

    @controller.pushObject @todoItem 

    afterEach -> 
    @view.destroy() 
    @controller.destroy() 
    @todoItem.destroy() 

    describe 'amount of todos', -> 

    beforeEach -> 
     # $('#konacha') is a div that gets cleaned between each test 
     Em.run => @view.appendTo '#konacha' 

    it 'is shown', -> 
     $('#konacha .todos-count').should.have.text '1 things to do' 

    it 'is livebound', -> 
     expect(=> $('#konacha .todos-count').text()).to.change.from('1 things to do').to('2 things to do').when => 
     Em.run => 
      extraTodoItem = store.createRecord TodoItem, 
      title: 'Moar todo' 
      @controller.pushObject extraTodoItem 

broken_template.handlebars

<div class="todos-count"><span class="todos">{{length}}</span> things to do</div> 

{{#linkTo "index"}}Home{{/linkTo}} 

working_template.handlebars

+1

基本的には、物事を個別にインスタンス化するのに問題があります。 Emberがあなたのアプリ全体を動かすことを望んでいる。これは答えではありませんが、一般的に私は単体テストよりも統合テストを好む([this video](http://www.youtube.com/watch?v=heK78M6Ql9Q)参照)。私は人々が孤立してビューをテストしようとしているのを見てきましたが、それがうまくいっても良い戦略のようには見えません。その背後にある理由のいくつかについては、http://www.slideshare.net/jo_liss/testing-ember-apps/27を参照してください。 –

答えて

9
<div class="todos-count"><span class="todos">{{length}}</span> things to do</div> 

私たちのソリューションは基本的にはアプリケーション全体をロードすることでしたが、テスト対象を可能な限り分離していました。例えば、ある

describe('FooView', function() { 
    beforeEach(function() { 
    this.foo = Ember.Object.create(); 
    this.subject = App.FooView.create({ foo: this.foo }); 
    this.subject.append(); 
    }); 

    afterEach(function() { 
    this.subject && this.subject.remove(); 
    }); 

    it("renders the foo's favoriteFood", function() { 
    this.foo.set('favoriteFood', 'ramen'); 
    Em.run.sync(); 
    expect(this.subject.$().text()).toMatch(/ramen/); 
    }); 
}); 

は、ルータや他のグローバルが可能ですので、完全に隔離ではありませんが、我々は簡単にテスト中の近くにオブジェクトへのもののためにダブルスで送信することができます。その後、

あなたが本当にルータを特定したい場合は、linkToヘルパーはcontroller.routerとしてそれを調べ、あなたができるので、あなたはこれを扱うことができる

this.router = { 
    generate: jasmine.createSpy(...) 
}; 

this.subject = App.FooView.create({ 
    controller: { router: this.router }, 
    foo: this.foo 
}); 
1

一つの方法は、linkToヘルパーのスタブを作成することで、 beforeブロックで使用します。これにより、実際のリンクの余分な要件(たとえば、ルーティング)がすべて迂回され、ビューの内容に集中できるようになります。私がそれをやっている方法は次のとおりです。

// Test helpers 
TEST.stubLinkToHelper = function() { 
    if (!TEST.originalLinkToHelper) { 
     TEST.originalLinkToHelper = Ember.Handlebars.helpers['link-to']; 
    } 
    Ember.Handlebars.helpers['link-to'] = function(route) { 
     var options = [].slice.call(arguments, -1)[0]; 
     return Ember.Handlebars.helpers.view.call(this, Em.View.extend({ 
      tagName: 'a', 
      attributeBindings: ['href'], 
      href: route 
     }), options); 
    }; 
}; 

TEST.restoreLinkToHelper = function() { 
    Ember.Handlebars.helpers['link-to'] = TEST.originalLinkToHelper; 
    TEST.originalLinkToHelper = null; 
}; 

// Foo test 
describe('FooView', function() { 
    before(function() { 
     TEST.stubLinkToHelper(); 
    }); 

    after(function() { 
     TEST.restoreLinkToHelper(); 
    }); 

    it('renders the favoriteFood', function() { 
     var view = App.FooView.create({ 
      context: { 
       foo: { 
        favoriteFood: 'ramen' 
       } 
      } 
     }); 

     Em.run(function() { 
      view.createElement(); 
     }); 

     expect(view.$().text()).to.contain('ramen'); 
    }); 
}); 
関連する問題