8

Ich versuche, einen Komponententest zu schreiben, der bestätigt, dass $rootScope.$broadcast('myApiPlay', { action : 'play' }); aufgerufen wird. Hier

ist die myapi.js

angular.module('myApp').factory('MyApi', function ($rootScope) { 
    var api = {}; 
    api.play = function() { 
     $rootScope.$broadcast('myApiPlay', { action : 'play' }); 
    } 
    return api; 
}); 

Und hier ist meine Einheit Test:

describe('Service: MyApi', function() { 

    // load the service's module 
    beforeEach(module('myApp')); 

    // instantiate service 
    var MyApi; 
    var rootScope; 

    beforeEach(function() { 
     inject(function ($rootScope, _MyApi_) { 
      MyApi = _MyApi_; 
      rootScope = $rootScope.$new(); 
     }) 
    }); 
    it('should broadcast to play', function() { 
     spyOn(rootScope, '$broadcast').andCallThrough(); 
     rootScope.$on('myApiPlay', function (event, data) { 
      expect(data.action).toBe('play'); 
     }); 
     MyApi.play(); 
     expect(rootScope.$broadcast).toHaveBeenCalledWith('myApiPlay'); 
    }); 
}); 

Hier ist der Fehler, den ich bekommen habe, während grunt test ausgeführt wird:

PhantomJS 1.9.7 (Windows 7) Service: MyApi should broadcast to pause FAILED 
     Expected spy $broadcast to have been called with [ 'myApiPlay' ] but it was never called. 

Ich habe auch mit expect(rootScope.$broadcast).toHaveBeenCalled() versucht und ich habe einen ähnlichen Fehler: Expected spy $broadcast to have been called..

Ich möchte überprüfen, dass diese Methode tatsächlich mit den richtigen Parametern aufgerufen wurde.

Vielen Dank!

+0

Haben Sie müssen nur die Reihenfolge wechseln? Sie müssen möglicherweise erwarten, bevor es tatsächlich aufgerufen wird, in Ihrem Fall rufen Sie es an und erwarten es dann. Sie können diesen Anruf auch bestätigen. – hassassin

+0

Ich habe den Auftrag umgestellt, gleicher Fehler. – Andrea

Antwort

14

Der Grund Ihrer Tests passieren, werden nicht, weil man auf der falschen $ Broadcast-Funktion Spionage werden. In Ihrem beforeJeach-Setup fragen Sie, ob der $ rootScope injiziert werden soll, und dann erstellen Sie einen Child-Bereich, indem Sie $ rootScope. $ New() aufrufen.

Der Rückgabewert von $ rootScope. $ New() ist nicht länger das rootScope, sondern ein untergeordnetes Element des Stammbereichs.

beforeEach(function() { 
    //inject $rootScope 
    inject(function ($rootScope, _MyApi_) { 
     MyApi = _MyApi_; 
     //create a new child scope and call it root scope 
     rootScope = $rootScope.$new(); 
     //instead don't create a child scope and keep a reference to the actual rootScope 
     rootScope = $rootScope; 
    }) 
}); 

In Ihrer Play-Funktion, die Sie anrufen $ Sendung auf dem $ rootScope aber in Ihrem Test spionieren Sie auf ein Kind von $ rootScope.

$rootScope.$broadcast('myApiPlay', { action : 'play' }); 

So ist es einpacken, um den Anruf zu $ ​​rootScope entfernen. $ New() und Spion nur auf dem $ rootScope der Injektor Dir gegeben hat. Das $ rootScope, das für Ihren Komponententest bereitgestellt wird, ist das gleiche $ rootScope, das für Ihren API-Dienst bereitgestellt wird. Daher sollten Sie direkt auf $ rootScope spionieren.

Schauen Sie sich die plunkr http://plnkr.co/edit/wN0m8no2FlKf3BZKjC4k?p=preview

+2

Dies ist in Ordnung für 'expect (rootScope. $ Broadcast) .toHaveBeenCalledWith ('myApiPlay', {aktion: 'play'});' aber das wird nicht erwartet: 'rootScope. $ On ('myApiPlay', Funktion (event , Daten) {expect (data.action) .toBe ('play');}); ' – Andrea

+1

Sie brauchen diesen Test nicht. Dieser Test testet den eckigen Rahmen und nicht die Geschäftslogik selbst. Sie können davon ausgehen, dass beim Aufruf von rootScope. $ Broadcast die Listener, die $ on verwenden, korrekt aufgerufen werden, da AngularJS so funktioniert – jcruz

+0

alles, was Sie wirklich testen müssen, ist $ rootScope.$ broadcast wurde mit den erwarteten Parametern – jcruz

1

Es wird für Sie hilfreich sein https://stackoverflow.com/a/17227264/2594499 Ihr Test ist nicht klar. Vermeiden Sie "erwarten" in Bedingungen, Rückrufe und solche Dinge. Wenn Ihre Bedingung nicht wahr ist, haben Sie Test ohne Behauptung.

Es wird besser sein zweiter Parameter der Funktion zu verwenden:

.toHaveBeenCalledwith('someEvent', someObj); 
+0

Hallo, ich mache das wie du sagst, aber der Unit Test sagt, dass es nicht aufgerufen wird. Ich teste, dass beim Aufruf von 'MyApi.play()' die Nachricht gesendet wird. – Andrea

Verwandte Themen