Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在backbone.js中正确测试路由器?_Javascript_Backbone.js_Jasmine_Sinon - Fatal编程技术网

Javascript 在backbone.js中正确测试路由器?

Javascript 在backbone.js中正确测试路由器?,javascript,backbone.js,jasmine,sinon,Javascript,Backbone.js,Jasmine,Sinon,因此,我刚刚开始使用sinon.js和jasmine.js为我正在开发的javascript应用程序编写测试。总体来说工作得很好,但我还需要能够测试我的路由器 路由器在其当前状态下,将触发大量视图和其他内容,通过调用主干网来终止当前的jasmine.js测试。导航取决于应用程序状态和UI生成 那么,我如何测试路由到不同位置是否有效,同时保持路由器“沙盒”状态,不允许它们更改路由 我可以设置某种模拟函数来监视pushState更改或类似更改吗?您必须模拟Backbone.Router.route,

因此,我刚刚开始使用
sinon.js
jasmine.js
为我正在开发的javascript应用程序编写测试。总体来说工作得很好,但我还需要能够测试我的路由器

路由器在其当前状态下,将触发大量视图和其他内容,通过调用
主干网来终止当前的
jasmine.js
测试。导航取决于应用程序状态和UI生成

那么,我如何测试路由到不同位置是否有效,同时保持路由器“沙盒”状态,不允许它们更改路由


我可以设置某种模拟函数来监视pushState更改或类似更改吗?

您必须模拟Backbone.Router.route,这是内部用于将函数绑定到Backbone.History的函数

这就是最初的功能:

route : function(route, name, callback) {
  Backbone.history || (Backbone.history = new Backbone.History);
  if (!_.isRegExp(route)) route = this._routeToRegExp(route);
  Backbone.history.route(route, _.bind(function(fragment) {
    var args = this._extractParameters(route, fragment);
    callback.apply(this, args);
    this.trigger.apply(this, ['route:' + name].concat(args));
  }, this));
}
您可以这样做,在路由器初始化时只需调用函数:

Backbone.Router.route = function(route, name, callback) {
    callback();
}
您还可以将回调保存在对象中,并将路由作为名称,然后逐步调用相同的步骤:

var map = {}
Backbone.Router.route = function(route, name, callback) {
    map[route] = callback();
}

for(i in map){
    map[i]();
}

关于测试主干网,有一个非常好的教程:


这里有一个低层次的jasmine测试方法,测试pushState是否按预期工作,以及路由器是否正确设置。。。 我假设一个
路由器
已经初始化,并且有一个主路由映射到“”。您可以将其用于其他路线。我还假设您已经在应用程序初始化中完成了一个
Backbone.history.start({pushState:true})

通过执行
Backbone.history.stop(),可以有效地实现类似的功能就是为了这个原因

更新:没有
pushState的浏览器

如果您测试的浏览器支持
pushState
,这当然可以正常工作。如果针对不支持的浏览器进行测试,则可以有条件地进行以下测试:

it('triggers the "home" route', function () {
    var home = spyOn(router, 'home').andCallThrough();

    if (Backbone.history._hasPushState) {
        pushStateSpy = spyOn(window.history, 'pushState').andCallFake(function (data, title, url) {
            expect(url).toEqual('/');
            router.home();
        });
        router.navigate('', {trigger: true});
        expect(pushStateSpy).toHaveBeenCalled();
        expect(home).toHaveBeenCalled();

    } else if (Backbone.history._wantsHashChange) {
        var updateHashSpy = spyOn(Backbone.history, '_updateHash').andCallFake(function (loc, frag) {
            expect(frag).toEqual('');
            router.home();
        });
        router.navigate('', {trigger: true});
        expect(updateHashSpy).toHaveBeenCalled();
        expect(home).toHaveBeenCalled();
    }
});

如果您使用的是IE6,祝您好运。

以下是我使用自己的结果。我制作了路由器的模拟版本,通过扩展它并用空白方法覆盖这些方法来防止它在被调用时调用任何进一步的逻辑:

describe("routers/main", function() {

    beforeEach(function() {

        // Create a mock version of our router by extending it and only overriding
        // the methods
        var mockRouter = App.Routers["Main"].extend({
            index: function() {},
            login: function() {},
            logoff: function() {}
        });

        // Set up a spy and invoke the router
        this.routeSpy = sinon.spy();
        this.router = new mockRouter;

        // Prevent history.start from throwing error
        try {
            Backbone.history.start({silent:true, pushState:true});
        } catch(e) {

        }

        // Reset URL
        this.router.navigate("tests/SpecRunner.html");
    });

    afterEach(function(){
        // Reset URL
        this.router.navigate("tests/SpecRunner.html");
    });

    it('Has the right amount of routes', function() {
        expect(_.size(this.router.routes)).toEqual(4);
    });

    it('/ -route exists and points to the right method', function () {
        expect(this.router.routes['']).toEqual('index');
    });

    it("Can navigate to /", function() {
        this.router.bind("route:index", this.routeSpy);
        this.router.navigate("", true);
        expect(this.routeSpy.calledOnce).toBeTruthy();
        expect(this.routeSpy.calledWith()).toBeTruthy();
    });

});

请注意,上面使用了
sinon.js
来创建spy,并使用
下划线.js
来提供
大小
函数。

当我测试主干路由器时,我关心的是我提供的路由正在调用我用正确参数指定的函数。这里的许多其他答案并没有真正验证这一点

如果需要测试某些路由的功能,可以自行测试这些功能

假设您有一个简单的路由器:

App.Router = Backbone.Router.extend({
  routes: {
    '(/)':'index',
    '/item/:id':'item'
  },
  index: {
    //render some template
  }, 
  item: {
    //render some other template, or redirect, or _whatever_
  }
});
我是这样做的:

describe('Router', function() {

  var trigger = {trigger: true};
  var router

  beforeEach(function() {
    // This is the trick, right here:
    // The Backbone history code dodges our spies
    // unless we set them up exactly like this:
    Backbone.history.stop(); //stop the router
    spyOn(Router.prototype, 'index'); //spy on our routes, and they won't get called
    spyOn(Router.prototype, 'route2'); 

    router = new App.Router(); // Set up the spies _before_ creating the router
    Backbone.history.start();
  });

  it('empty route routes to index', function(){
    Backbone.history.navigate('', trigger);
    expect(router.index).toHaveBeenCalled();
  });

  it('/ routes to index', function(){
    router.navigate('/', trigger);
    expect(router.index).toHaveBeenCalled();
  });

  it('/item routes to item with id', function(){
    router.navigate('/item/someId', trigger);
    expect(router.item).toHaveBeenCalledWith('someId');
  });
});
我开始使用的是微软的解决方案,即监视
\u updateHash
,这在一定程度上对我起了作用。但是,我发现我的测试很混乱,因为哈希从未更新,所以依赖于调用
getHash
getFragment
的代码失败了

我最后得到的是以下helper函数,它同时监视
\u updateHash
getHash
。前者记录更新散列的请求,后者返回传递给
\u updateHash
的最后一个散列。在开始主干历史记录之前,我在测试中调用这个helper函数

    /**
     * Prevent Backbone tests from changing the browser's URL.
     *
     * This function modifies Backbone so that tests can navigate
     * without modifying the browser's URL. It works be adding
     * stub versions of Backbone's hash functions so that updating
     * the hash doesn't change the URL but instead updates a
     * local object. The router's callbacks are still invoked
     * so that to the test it appears that navigation is behaving
     * as expected.
     *
     * Note: it is important that tests don't update the browser's
     * URL because subsequent tests could find themselves in an
     * unexpected navigation state.
     */
    preventBackboneChangingUrl = function() {
        var history = {
            currentFragment: ''
        };

        // Stub out the Backbone router so that the browser doesn't actually navigate
        spyOn(Backbone.history, '_updateHash').andCallFake(function (location, fragment, replace) {
            history.currentFragment = fragment;
        });

        // Stub out getHash so that Backbone thinks that the browser has navigated
        spyOn(Backbone.history, 'getHash').andCallFake(function () {
            return history.currentFragment;
        });
    };

赏金开始了!期待更多关于这方面的想法,谢谢。我已经看到了,但这对我回避路由器调用重定向等事实没有帮助…嗨,安德烈亚斯。仍然无法让它与您的代码一起工作-路由器方法中的逻辑仍然没有停止!这看起来不错,但我看不出这是如何阻止来自
router.home()
内部的实际逻辑调用的,如上所述,关键是阻止历史更改您的位置。你可以通过监视window.history,验证它是否工作,然后在不改变位置的情况下调用路由器来实现这一点。然后,在上面的示例中,您可以检查home()是否创建了视图、更改了DOM或您正在执行的任何操作。如果您还想进入router.home()中的登录,当然可以通过:homepy=spyOn(router,'home')。和callfake(…);但是没有间谍,你永远也到不了那里。但是,使用此解决方案获取路由方法的最终URI参数如何?您可以检查spies中的所有内容不?我知道这是一个较老的问题,但它在Google搜索结果中排名靠前,我认为人们可以做得更好。请看下面我的答案。这正是我想要的。谢谢你的在线评论,解释了你的理由!
    /**
     * Prevent Backbone tests from changing the browser's URL.
     *
     * This function modifies Backbone so that tests can navigate
     * without modifying the browser's URL. It works be adding
     * stub versions of Backbone's hash functions so that updating
     * the hash doesn't change the URL but instead updates a
     * local object. The router's callbacks are still invoked
     * so that to the test it appears that navigation is behaving
     * as expected.
     *
     * Note: it is important that tests don't update the browser's
     * URL because subsequent tests could find themselves in an
     * unexpected navigation state.
     */
    preventBackboneChangingUrl = function() {
        var history = {
            currentFragment: ''
        };

        // Stub out the Backbone router so that the browser doesn't actually navigate
        spyOn(Backbone.history, '_updateHash').andCallFake(function (location, fragment, replace) {
            history.currentFragment = fragment;
        });

        // Stub out getHash so that Backbone thinks that the browser has navigated
        spyOn(Backbone.history, 'getHash').andCallFake(function () {
            return history.currentFragment;
        });
    };