Sinon.js和Backbone - 测试视图方法调用

时间:2013-09-20 18:31:27

标签: unit-testing backbone.js sinon

我在使用Jasmine和Sinon的现有Backbone应用程序的测试套件上工作,我正在测试我的路由器在某个路由上执行正确的操作。这是实际的路线功能:

favourites: function()
{
    //Dont re-initialize the favourites view as there is no need.
    //Instead, just render the favourite movies
    if ( ! this.favMoviesView)
    {
        this.favMoviesView = new cinephile.Views.FavouriteMoviesView({
            collection: cinephile.favouriteMovies
        });
    }
    else
    {
        this.favMoviesView.renderFavourites();
    }

    $('#content').html(this.favMoviesView.el);
},

在我的测试套件中,我想声明当导航到收藏夹路线this.favMoviesView时会创建一次然后,如果它存在则不会重新初始化,而只是调用this.favMoviesView.renderFavourites(),这是迭代视图集合的方法。

这是我的测试规范:

describe('cinephile.Routers.CinephileRouter', function () {

    beforeEach(function () {

        this.router = new cinephile.Routers.CinephileRouter();
        this.routeSpy = sinon.spy();

        try
        {
            Backbone.history.start({ silent : true });
        }
        catch(e) {}

        this.router.navigate('elsewhere');

        this.favouritesViewStub = sinon.stub(cinephile.Views, 'FavouriteMoviesView')
            .returns(new Backbone.View());
    });

    afterEach(function () {
        this.favouritesViewStub.restore();
    });

    describe('Favourites Route', function() {

        it('should load the favourites on /favourites', function () {

            this.router.bind('route:favourites', this.routeSpy);
            this.router.navigate('favourites', true);

            expect(this.routeSpy.calledOnce).toBeTruthy();
            expect(this.routeSpy.calledWith()).toBeTruthy();
        });

        it('creates a favourites view if one doesn\'t exist', function () {
            this.router.favourites();
            expect(this.favouritesViewStub.calledOnce).toBeTruthy();
        });

        it('Reuses the favourites view if one does exist and reset it\'s collection', function () {
            this.router.favourites();
            this.router.favourites();

            expect(this.favouritesViewStub.calledOnce).toBeTruthy();
            expect(this.favouritesViewStub.renderFavourites).toHaveBeenCalledTwice();
        }); 
    });
});

我的前两个测试通过,我相信它们能正确描述路由器中的favourites方法。第三个测试就是那个给我带来问题的测试。据我了解,因为我正在测试我的路由器而不是FavouriteMoviesView我应该删除视图以保持测试隔离。如果这是正确的假设,我的问题就是存根将不会有renderFavourites方法,因为它是一个存根Backbone.View()

我如何解决这个特殊问题,如果你如此倾向,我相信我会遗漏一些概念,所以请随意解释一下我不理解的问题。

干杯。

1 个答案:

答案 0 :(得分:1)

你的问题是你想在mock函数中模拟一些东西。我建议的是,而不是这个......

this.favouritesViewStub = sinon.stub(cinephile.Views, 'FavouriteMoviesView').returns(new Backbone.View());

......有这个:

var StubView = Backbone.View.extend({
  renderFavourites: sinon.stub()
});
this.favouritesViewStub = sinon.stub(cinephile.Views, 'FavouriteMoviesView').returns(new StubView());

现在你的View"构造函数"将返回StubView,其中包含您调用的方法。所以这个带有stubbed out方法的Backbone View将放在router.favMoviesView -property中。 favouritesViewStub属性仍然只包含"构造函数" -function,因此您无法从那里访问此存根方法。这就是你必须从上一次测试中改变它的原因:

expect(this.favouritesViewStub.renderFavourites).toHaveBeenCalledTwice();

这样的事情:

expect(this.router.favMoviesView.renderFavourites).toHaveBeenCalledTwice();

通过这种方式,您将实际检查路由器的视图副本是否已将方法调用两次。

希望这对你有用,如果没有,请评论!我没有对此进行测试,因此可能存在一些问题,但我确信其背后的逻辑是有效的。