2013-03-26 4 views
13

Ho bisogno della mia app per eseguire alcune configurazioni in fase di esecuzione vi un endpoint HTTP.Test unitario durante il caricamento di elementi nell'app eseguita con AngularJS

Ho scritto un servizio semplice per farlo:

module.factory('config', function ($http, analytics) { 
    return { 
     load: function() { 
      $http.get('/config').then(function (response) { 
       analytics.setAccount(response.googleAnalyticsAccount); 
      }); 
     } 
    } 
}); 

Avanti, io chiamo questo modulo in un blocco corsa di mio modulo app:

angular.module('app').***.run(function(config) { 
     config.load(); 
    }); 

tutto funziona bene quando l'applicazione è in esecuzione ma nei miei test unitari, ottengo questo errore: "Errore: richiesta inaspettata: GET/config"

So cosa significa ma non so come deriderlo quando succede da un blocco di corsa.

Grazie per il vostro aiuto

EDIT per aggiungere spec

chiamata a questo prima di ogni

beforeEach(angular.mock.module('app')); 

Abbiamo provato questo per deridere $ httpBackend:

beforeEach(inject(function($httpBackend) { 

    $httpBackend.expectGET('/config').respond(200, {'googleAnalyticsAccount':}); 

    angular.mock.module('app') 

    $httpBackend.flush(); 
})); 

Ma ottenuto:

TypeError: Cannot read property 'stack' of null 
     at workFn (/Users/arnaud/workspace/unishared-dredit/test/lib/angular/angular-mocks.js:1756:55) 
    TypeError: Cannot read property 'stack' of null 
     at workFn (/Users/arnaud/workspace/unishared-dredit/test/lib/angular/angular-mocks.js:1756:55) 
    TypeError: Cannot read property 'stack' of null 
     at workFn (/Users/arnaud/workspace/unishared-dredit/test/lib/angular/angular-mocks.js:1756:55) 

EDIT dall'aggiornamento per AngularJS 1.0.6

Da quando ho aggiornato a 1.0.6 AngularJS, consigliato da Igor dal team angolare, il problema è andato, ma ora ora ho questo, che suona più "normale" ma non riesco ancora a capire come farlo funzionare.

Error: Injector already created, can not register a module! 
+2

Ho anche questo errore durante il test di 'run()' – halfcube

+0

L'ho infine spostato nel mio controller di root dell'applicazione per renderlo testabile. –

risposta

16

Ho faticato con questo errore per un po ', ma sono riuscito a trovare una soluzione ragionevole.

Quello che volevo ottenere è quello di arrestare correttamente il servizio e forzare una risposta, sui controller era possibile utilizzare $httpBackend con una richiesta di stub o eccezione prima di avviare il controller. In app.run() quando si carica il module inizializza l'oggetto ed è collegato Servizi ecc.

Sono riuscito a stubare il servizio utilizzando il seguente esempio.

describe('Testing App Run', function() { 
    beforeEach(module('plunker', function ($provide) { 
     return $provide.decorator('config', function() { 
      return { 
       load: function() { 
        return {}; 
       } 
      }; 
     }); 
    })); 


    var $rootScope; 
    beforeEach(inject(function (_$rootScope_) { 
     return $rootScope = _$rootScope_; 
    })); 

    it("defines a value I previously could not test", function() { 
     return expect($rootScope.value).toEqual('testing'); 
    }); 

}); 

Spero che questo aiuti il ​​tuo test app.run() in futuro.

+0

Si noti che il decoratore "config" non si riferisce allo stadio di configurazione angolare, ma al servizio di fabbrica OP ha chiamato "config" – ErikAGriffin

+0

Questo è stato scritto intorno al tempo di Angular 1.0.5, quindi l'API potrebbe essere cambiata un po 'da allora. – halfcube

1

Si dovrebbe prendere in giro ogni richiesta HTTP con ngMock.$httpBackend. Inoltre, here is a guide.


Aggiornamento

Non è necessario la cosa angular.mock.module, solo bisogno di iniettare il modulo app. Qualcosa di simile a questo:

var httpBackend; 

beforeEach(module('app')); 
beforeEach(inject(function($httpBackend) { 
    httpBackend = $httpBackend; 
    $httpBackend.expectGET('/config').respond(200, {'googleAnalyticsAccount': 'something'}); 
})); 

Nei vostri test, quando è necessario il http deriso per rispondere, si chiamerà httpBackend.flush(). Questo è il motivo per cui abbiamo un riferimento ad esso, quindi non è necessario iniettarlo in ogni singolo test che hai.

Nota per poter funzionare, è necessario caricare angular-mock.js.

+0

Grazie per la risposta. Se faccio qualche iniezione prima di chiamare angular.mock.module, ricevo un errore che dice che l'iniettore è già stato creato. –

+0

Pubblica le specifiche correlate, per favore. –

+0

Appena pubblicato, grazie per il vostro aiuto! –

5

Non so se si sta ancora cercando una risposta a questa domanda. Ma ecco alcune informazioni che potrebbero aiutare.

$ injector è un singleton per un'applicazione e non per un modulo. Tuttavia, angular.injector in realtà cercare di creare un nuovo iniettore per ciascun modulo (I supponiamo di avere un

beforeEach(module("app")); 

all'inizio.

Ho avuto lo stesso problema durante l'utilizzo angolare, RequireJS, Karma e Jasmine ed io abbiamo escogitato due modi per risolverlo: ho creato un fornitore per la funzione di iniettore come dipendenza separata dai miei test.Ad esempio MyInjectorProvider che fornisce un'istanza singleton di $ injector

L'altro modo era spostare il fornitore dichiarazioni seguenti:

beforeEach(module("app")); 
beforeEach(inject(function($injector){ 
    ... 
}) 

all'interno della descrizione della suite di test. Quindi, ecco come appariva prima:

define(['services/SignupFormValidator'], function(validator){ 
    var validator; 
    beforeEach(module("app")); 
    beforeEach(inject(function($injector){ 
     validator = $injector.get("SignupFormValidator"); 
    }) 

    describe("Signup Validation Tests", function(){ 
     it("...", function(){...}); 
    }); 
}); 

Dopo aver applicato la correzione sembra che questo:

define(['services/SignupFormValidator'], function(validator){ 
    var validator; 

    describe("Signup Validation Tests", function(){ 
     beforeEach(module("app")); 
     beforeEach(inject(function($injector){ 
      validator = $injector.get("SignupFormValidator"); 
     }); 

     it("...", function(){...}); 
    }); 
}); 

Entrambe le soluzioni hanno lavorato nel mio caso.