2015-08-11 2 views
5

Ich habe einen eckigen Service verantwortlich für das Laden einer config.json Datei. Ich möchte es in meiner Run-Phase nennen, also setze ich dieses JSON in meinem $ rootContext und daher ist es in Zukunft für alle verfügbar.

Im Grunde ist das, was ich habe:

angular.module('app.core', []).run(function(CoreRun) { 
    CoreRun.run(); 
}); 

Wo ist mein CoreRun Service ist:

angular.module('app.core').factory('CoreRun', CoreRun); 

CoreRun.$inject = ['$rootScope', 'config']; 

function CoreRun($rootScope, config) { 
    function run() { 
    config.load().then(function(response) { 
     $rootScope.config = response.data; 
    }); 
    }  
    return { 
    run: run 
    }; 
} 

Dies funktioniert gut, und das Problem aufkommt, wenn ich zu Test versuchen es . Ich möchte meinen Config-Dienst ausspionieren, damit er ein falsches Versprechen zurückgibt. Allerdings kann ich es nicht machen, da während der Konfigurationsphase für meinen Test keine Dienste verfügbar sind und ich $ q nicht injizieren kann.

Soweit ich sehen kann, gibt es die einzige Chance, meinen Config-Dienst zu verspotten, in der Config-Phase, da es von run block aufgerufen wird.

Der einzige Weg, den ich bis jetzt gefunden habe, ist die Generierung des Versprechens mit jQuery, das ich wirklich nicht mag.

beforeEach(module('app.core')); 

var configSample; 

beforeEach(module(function ($provide) { 
    config = jasmine.createSpyObj('config', [ 'load' ]); 
    config.load.and.callFake(function() { 
    configSample = { baseUrl: 'someurl' };   
    return jQuery.Deferred().resolve({data: configSample}).promise(); 
    }); 
    provide.value('config', config); 
})); 

it('Should load configuration using the correspond service', function() { 
    // assert 
    expect(config.load).toHaveBeenCalled(); 
    expect($rootScope.config).toBe(configSample); 
}); 

Gibt es eine Möglichkeit, eine bessere Problemumgehung zu machen?

BEARBEITEN Sie: Wahrscheinlich lohnt es sich zu bemerken, dass dies ein Problem ist, nur wenn Unit-Test mein Lauf blockieren.

+1

mögliche Duplikate von [Can $ q und $ http im Abschnitt .config injiziert werden] (http://stackoverflow.com/questions/20626514/can-q-and-http-be-injected) -in-the-config-section) – Constantine

+0

Scheint ähnlich, aber komplett anders. Die eine, die Sie beziehen, ist über die Injektion von $ q in der Config-Phase eines realen Moduls. Hier geht es darum, $ q in einen Run-Block während der Config-Phase eines Unit-Tests zu injizieren, damit Sie sich darüber lustig machen können, dass Sie Ihren Run-Block testen können. – jbernal

Antwort

3

Scheint es ist nicht möglich, $q den richtigen Weg zu injizieren, weil die Funktion in Ihrem run() Block sofort feuert. run() Block gilt als eine Config-Phase in Angular, so inject() in Tests läuft nur nach Config-Blöcken, daher auch wenn Sie inject()$q im Test, wird es undefined sein, weil run() zuerst ausgeführt wird.

Nach einiger Zeit konnte ich $q im module(function ($provide) {}) Block mit einem sehr schmutzigen Workaround bekommen. Die Idee besteht darin, ein zusätzliches Winkelmodul zu erstellen und es in den Test vor Ihrem Anwendungsmodul einzubinden. Dieses zusätzliche Modul sollte auch einen run() Block haben, der $q in einem globalen Namespace veröffentlichen wird. Der Injektor wird zuerst die run() des zusätzlichen Moduls und dann die run() des Anwendungsmoduls aufrufen.

angular.module('global $q', []).run(function ($q) { 
    window.$q = $q; 
}); 

describe('test', function() { 

    beforeEach(function() { 

     module('global $q'); 

     module('app.core'); 

     module(function ($provide) { 
      console.log(window.$q); // exists 
     }); 

     inject(); 

    }); 
}); 

Dieses zusätzliche Modul kann als separate Datei für die Testsuite vor den Spec-Dateien eingefügt werden. Wenn Sie das Modul in die gleiche Datei wie die Tests einfügen, müssen Sie keine globale Variable window verwenden, sondern nur eine Variable in einer Datei.

Here is a working plunker (siehe "script.js" Datei)

Erste Lösung (löst nicht das Problem):

Sie können tatsächlich $q in diesem Fall benutzen, aber Sie haben es zu injizieren zu einer Testdatei. Hier injizieren Sie es nicht wirklich zu einer zu testenden Einheit, sondern direkt zu einer Testdatei, um es innerhalb des Tests verwenden zu können.Also es hängt tatsächlich nicht von der Art einer im Test befindlichen Einheit:

// variable that holds injected $q service 
var $q; 

beforeEach(module(function ($provide) { 
    config = jasmine.createSpyObj('config', [ 'load' ]); 

    config.load.and.callFake(function() { 
     var configSample = { baseUrl: 'someurl' }; 

     // create new deferred obj 
     var deferred = $q.defer(); 

     // resolve promise 
     deferred.resolve({ data: configSample }); 

     // return promise 
     return deferred.promise; 
    }); 

    provide.value('config', config); 
})); 

// inject $q service and save it to global (for spec) variable 
// to be able to access it from mocks 
beforeEach(inject(function (_$q_) { 
    $q = _$q_; 
})); 

Ressourcen:

Und noch eine Anmerkung : Config Phase und Lauf Phase sind zwei verschiedene Dinge. Config Block erlaubt nur Anbieter zu verwenden, aber in dem Lauf Block kann man so ziemlich alles injizieren (außer Provider). Weitere Informationen finden Sie hier - Module Loading & Dependencies

+0

Ja, natürlich. Ich kenne die Unterschiede zwischen ihnen. Ich wollte nur erwähnen, dass ich idealerweise $ q in die Config-Phase innerhalb meines Tests injizieren müsste, weil es vor meinem Run-Block läuft. – jbernal

+0

Danke für Ihre Antwort. Ich würde es versuchen, sobald ich kann. Ich möchte jedoch daran denken, es bereits getestet zu haben, und es hat nicht funktioniert, weil das zweite _beforeach_ ausgeführt wird, sobald mein Laufblock bereits ausgeführt wurde und daher zu diesem Zeitpunkt $ q undefiniert war. – jbernal

+0

In der Tat, es funktioniert nicht. Es könnte sein, weil ich '$ q' müssen injiziert wurden, wenn mein laufen Block ausgeführt wird (Trigger durch' before (Modul (‚app.core‘)); ') und in diesem Moment' before (injizieren (function (_ $ Q_) 'noch nicht geschehen. – jbernal

Verwandte Themen