2012-08-07 8 views
9

Probleme bei der Ausspähung Methode Anrufe auf einem Backbone-Router, um sicherzustellen, dass es die richtige Methode auf einer bestimmten Route ruft.Ausspionieren Backbone.js Route Anrufe mit Jasmine

Auszug aus dem Test

describe 'Router', -> 
    beforeEach -> 
     @router = new App.Router() 
     Backbone.history.start() 

    afterEach -> 
     Backbone.history.stop() 

    describe 'routes', -> 
     it 'should be defined', -> 
       expect(@router.routes).toBeDefined() 

     describe 'default route', -> 
      it 'should be defined', -> 
        expect(@router.routes['']).toBeDefined() 

      it 'should call index', -> 
       spy = spyOn(@router, "index") 
       @router.navigate('', true) 
       expect(spy).toHaveBeenCalled() 

Der Router

class App.Router extends Backbone.Router 
    routes: 
     '' : 'index' 

    index: -> 
     console.log "router.index has been called" 

Alles geht außer dem letzten Test "sollte Index nennen". Es schlägt mit der Meldung "Erwarteter Spionage-Index wurde aufgerufen" fehl. Ive versucht, andere Varianten

it "should call index", -> 
    spyOn(@router, "index") 
    @router.navigate('', true) 
    expect(@router.index).toHaveBeenCalled() 

Ich kann auch das sehen Protokollausgabe in der Testausgabe von der ursprünglichen Router.index Funktion

Dank „router.index genannt wurde“!

EDIT: Eine Lösung

describe '#1 Solution', -> 
    it 'should call index', -> 
     spyOn(App.Router.prototype, "index") 
     @router = new App.Router() 
     Backbone.history.start() 
     @router.navigate('', true) 
     expect(App.Router.prototype.index).toHaveBeenCalled() 

Antwort

15

Es dauerte hat zu viel Zeit, um mit einem working jsFiddle zu kommen und die Frage wurde bereits von @MarkRushakoff beantwortet.

Noch habe ich einige Kommentare.

Der Weg, den Backbone die Routen bindet, macht es sehr schwierig, es zu testen.

Der Punkt ist, dass die Router Methoden sind nicht direkt in der Router-Instanz genannt wird, werden die Verfahren als taked Rückrufe und in einer internen Backbone.history.route zur Ausführung warten gespeichert, check the Backbone.Router.route code.

Dieser Vorgang wird in dem Moment getan die Router instantiate ist, so dass Sie Ihre Router.methodspy haben, bevor Sie die Referenz instanziiert, so dass für Sie Backbone.history.start auch verzögern, nachdem die spy aktiviert wurde.

Da Sie die spy deklarieren müssen, bevor die Router-Instanz erstellt wird, müssen Sie dies in einer Klasse Ebene tun.

Said so ist dies die einfachste Lösung kam ich mit:

describe("Router", function() { 
    afterEach(function(){ 
    Backbone.history.stop(); 
    }); 

    it("should call index", function(){ 
    spyOn(App.Router.prototype, "index") 
    var router = new App.Router(); // instance created after spy activation 
    Backbone.history.start();  // it has to start after the Router instance is created 

    router.navigate('', true); 

    expect(App.Router.prototype.index).toHaveBeenCalled(); 
    }); 
}); 

Fazit, ich glaube, die Backbone.Router Implementierung nicht ein intuitives Design.

+1

Danke! Sieht so aus, als ob das der richtige Weg ist :) – eldewall

+0

Dies ist kein praktikabler Weg, das Auslösen einer Route zu testen. Alles was getestet wird, ist, dass die Indexfunktion als Rückruf an den Router gebunden war, nicht dass die Funktion tatsächlich aufgerufen wurde, als die Route ausgelöst wurde. Siehe [diese S.O. Post] (http://stackoverflow.com/questions/9215737/testing-routers-in-backbone-js-properly), um zu überprüfen, ob die entsprechende Routenfunktion aufgerufen wurde, wenn ein Router mit einer URL übereinstimmt. – louism2

4

Ich bin mir ziemlich sicher, dass dies mit der Art und Weise zu tun, dass Backbone zu seinen Routing-Methoden bindet, wenn Sie eine Route-Hash verwenden (vor allem, wenn Sie eine Konsole sind zu sehen log korrekt ausgeben). Das heißt, der Router hat an die ursprüngliche index-Methode gebunden, aber Ihr Spion hat die "aktuelle" index-Methode ersetzt.

Sie haben zwei Möglichkeiten:

  • spyOn(@router, "index"), bevor Sie den Router an die Routen bindet (kann schwierig sein)
  • Spy auf der index Methode Prototyp: spyOn(App.router.prototype, "index"); @router.navigate('', true); expect(App.router.prototype.index).toHaveBeenCalled();
+0

Danke, das funktioniert :) Option Nummer zwei ist machbar. Der Spion muss hinzugefügt werden, bevor eine neue Instanz des Routers erstellt wird. Ich denke, das ist OK! – eldewall

+0

Option 1, die ich denke, ist nicht möglich, da die _routes binding_ in der _initialize_ gemacht wird, also in dem Moment, in dem Sie einen Verweis auf die Instanz haben, die Bindung wurde bereits durchgeführt. – fguillen

Verwandte Themen