8

Hat jemand eine Idee, wie man $ httpBackend in e2e eckigen Tests mockt? Die Idee ist, XHR-Anfragen während des Tests auf travis-ci zu unterdrücken. Ich benutze Karma, um Assets und Partials aus meiner Rails-App, die auf Travis läuft, zu requirieren. Ich möchte Akzeptanztests ohne echte DB-Abfragen durchführen.

Hier ist ein Teil meiner Karma-Konfigurationsdatei:

... 
files = [ 
    MOCHA, 
    MOCHA_ADAPTER, 

    'spec/javascripts/support/angular-scenario.js', 
    ANGULAR_SCENARIO_ADAPTER, 

    'spec/javascripts/support/angular-mocks.js', 
    'spec/javascripts/e2e/**/*_spec.*' 
]; 
... 

proxies = { 
    '/app': 'http://localhost:3000/', 
    '/assets': 'http://localhost:3000/assets/' 
}; 
... 

Hier ist ein Teil meiner spec-Datei:

beforeEach(inject(function($injector){ 
    browser().navigateTo('/app'); 
})); 

it('should do smth', inject(function($rootScope, $injector){ 
    input('<model name>').enter('smth'); 
    //this is the point where I want to stub real http query 
    pause(); 
})); 

Ich habe versucht, $ erhalten httpBackend Service über $ Injektor:

$injector.get('$httpBackend') 

Aber das ist nicht das, das innerhalb Iframe verwendet wird, wo meine Tests laufen.

Der nächste Versuch machte ich wurde angular.scenario.dsl verwenden, hier ist der Code samle:

angular.scenario.dsl('mockHttpGet', function(){ 
    return function(path, fakeResponse){ 
    return this.addFutureAction("Mocking response", function($window, $document, done) { 
     // I have access to window and document instances 
     // from iframe where my tests run here 
     var $httpBackend = $document.injector().get(['$httpBackend']); 
     $httpBackend.expectGET(path).respond(fakeResponse) 
     done(null); 
    }); 
    }; 
}); 

Anwendungsbeispiel:

it('should do smth', inject(function($rootScope, $injector){ 
    mockHttpGet('<path>', { /* fake data */ }); 
    input('search.name').enter('mow'); 
    pause(); 
})); 

Dies führt zu folgenden Fehler:

<$httpBackend listing> has no method 'expectGET' 

Also, an diesem Punkt habe ich keine Ahnung vom nächsten Schritt. Hat jemand versucht, so etwas zu tun, ist diese Art von Stubbing wirklich möglich?

+0

Wie konfigurieren Sie Ihr Karma, um "inject" -Funktion in Ihrer Spezifikation zu haben? Ich habe immer ReferenceError für meine Tests bekommen – wakandan

Antwort

0

Dies fühlt sich eher wie Unit/Spec-Tests. Im Allgemeinen sollten Sie Mocks innerhalb von Unit/Spec-Tests anstelle von E2e/Integrationstests verwenden. Im Grunde denken Sie an e2e-Tests, wie Sie die Erwartungen an eine meist integrierte App erfüllen ... wenn Sie sich über Dinge lustig machen, die den Zweck des e2e-Tests besiegen. In der Tat bin ich nicht sicher, wie Karam Angular-mocks.js in die laufende App einfügen würde.

Die Spezifikation Test etwas aussehen könnte ...

describe('Controller: MainCtrl', function() { 
    'use strict'; 

    beforeEach(module('App.main-ctrl')); 

    var MainCtrl, 
     scope, 
     $httpBackend; 

    beforeEach(inject(function ($controller, $rootScope, $injector) { 
     $httpBackend = $injector.get('$httpBackend'); 
     $httpBackend.when('GET', '/search/mow').respond([ 
      {} 
     ]); 
     scope = $rootScope.$new(); 
     MainCtrl = $controller('MainCtrl', { 
      $scope: scope 
     }); 
    })); 

    afterEach(function() { 
     $httpBackend.verifyNoOutstandingExpectation(); 
     $httpBackend.verifyNoOutstandingRequest(); 
    }); 

    it('should search for mow', function() { 
     scope.search = 'mow'; 
     $httpBackend.flush(); 
     expect(scope.accounts.length).toBe(1); 
    }); 
}); 
+0

Der Code steht nicht in Zusammenhang mit der Frage - die Frage bezieht sich nicht auf Komponententests und der Code ist für Jasmin-Komponententests. 'inject' ist in e2e-Tests nicht definiert. –

7

Wenn Sie wirklich das Backend in einem E2E Test zu verspotten versuchen (diese Tests Szenarien genannt werden, während Specs für Unit-Tests verwendet werden) dann habe ich das in einem Projekt gemacht, an dem ich früher gearbeitet habe.

Die Anwendung, die ich getestet habe, hieß studentsApp. Es war eine Anwendung, um nach Studenten zu suchen, indem eine REST API abgefragt wurde. Ich wollte die Anwendung testen, ohne diese API tatsächlich abzufragen.

Ich erstellte eine E2E-Anwendung namens studentsAppDev, die ich injiziere studentsApp und ngMockE2E in. Dort definiere ich, welche Aufrufe das mockBackend erwarten soll und welche Daten zurückgegeben werden sollen. Im Folgenden ist ein Beispiel für meine studentsAppDev Datei:

"use strict"; 

// This application is to mock out the backend. 
var studentsAppDev = angular.module('studentsAppDev', ['studentsApp', 'ngMockE2E']); 
studentsAppDev.run(function ($httpBackend) { 

    // Allow all calls not to the API to pass through normally 
    $httpBackend.whenGET('students/index.html').passThrough(); 

    var baseApiUrl = 'http://localhost:19357/api/v1/'; 
    var axelStudent = { 
     Education: [{...}], 
     Person: {...} 
    }; 
    var femaleStudent = { 
     Education: [{...}], 
     Person: {...} 
    }; 
    $httpBackend.whenGET(baseApiUrl + 'students/?searchString=axe&') 
     .respond([axelStudent, femaleStudent]); 
    $httpBackend.whenGET(baseApiUrl + 'students/?searchString=axel&')  
     .respond([axelStudent, femaleStudent]); 
    $httpBackend.whenGET(baseApiUrl + 'students/?searchString=axe&department=1&') 
     .respond([axelStudent]); 
    $httpBackend.whenGET(baseApiUrl + 'students/?searchString=axe&department=2&') 
     .respond([femaleStudent]); 
    $httpBackend.whenGET(baseApiUrl + 'students/?searchString=axe&department=3&')  
     .respond([]); 

    ... 

    $httpBackend.whenGET(baseApiUrl + 'departments/?teachingOnly=true') 
     .respond([...]); 
    $httpBackend.whenGET(baseApiUrl + 'majors?organization=RU').respond([...]); 
}); 

Dann habe ich einen ersten Schritt in meinem Jenkins CI-Server die studentsApp mit studentsAppDev und fügen Sie einen Verweis auf angular-mocks.js in der Haupt index.html Datei zu ersetzen.

+3

Sie müssen keine separate App einrichten und erstellen, nur um $ httpBackend zu verspotten. Ich habe beschrieben, wie es eingerichtet wird, so dass es für beide Einheit & E2E-Test insgesamt hier verwendet werden kann: http://blogs.burnsidedigital.com/2013/09/and-httpbackend-mock-for-all-unit-e2e- Prüfungen /. – Dida

+0

Oh, das ist eine gute Lösung Dida, danke dafür schreiben. Es ist definitiv etwas, auf das ich mich für das nächste Mal konzentrieren werde, wenn ich das Backend verspotten muss. –

+0

@Dida Link oben funktioniert jetzt nicht.Kannst du kurz erklären, was du getan hast? Vielleicht als neue Antwort. Vielen Dank. – Ena

1

Das Ausspionieren Ihres Backends ist ein wichtiger Schritt beim Aufbau einer komplexen Angular-Anwendung.Es ermöglicht das Testen ohne Zugriff auf das Backend, Sie testen die Dinge nicht zweimal und es gibt weniger Abhängigkeiten, um die Sie sich kümmern müssen.

Angular Multimocks ist eine einfache Möglichkeit zu testen, wie sich Ihre App mit unterschiedlichen Antworten von einer API verhält.

Sie können Sets von Mock-API-Antworten für verschiedene Szenarien als JSON-Dateien definieren.

Es ermöglicht Ihnen auch, Szenarien leicht zu ändern. Es ermöglicht Ihnen, Sie "Szenarien" aus verschiedenen Mock-Dateien zu erstellen.

Wie es zu Ihrer App

Nach dem Hinzufügen der benötigten Dateien in die Seite, fügen Sie einfach scenario als Abhängigkeit Ihrer Anwendung hinzuzufügen:

angular 
    .module('yourAppNameHere', ['scenario']) 
    // Your existing code here... 

Sobald Sie dies zu Ihrer App haben Sie kann beginnen, Mocks für API-Aufrufe zu erstellen.

Lets sagen, dass Ihre App die folgenden API-Aufruf macht:

$http.get('/games').then(function (response) { 
    $scope.games = response.data.games; 
}); 

können Sie erstellen eine default Mock-Datei:

Beispiel someGames.json

{ 
    "httpMethod": "GET", 
    "statusCode": 200, 
    "uri": "/games", 
    "response": { 
    "games": [{"name": "Legend of Zelda"}] 
    } 
} 

Wenn Sie Ihre Anwendung laden, Anrufe zu /games wird 200 und {"games": [{"name": "Legend of Zelda"}]}

zurückgeben

Nehmen wir an, Sie möchten eine andere Antwort für denselben API-Aufruf zurückgeben. Sie können die Anwendung in einem anderen Szenario platzieren, indem Sie die URL z. ?scenario=no-games

Das no-games Szenario eine andere Mock-Datei verwenden kann, lässt man wie folgt sagen:

Beispiel noGames.json

{ 
    "httpMethod": "GET", 
    "statusCode": 200, 
    "uri": "/games", 
    "response": { 
    "games": [] 
    } 
} 

Nun, wenn Sie Ihre Anwendung laden, ruft /games wird 200 und {"games": []} zurückkehren

Szenarien bestehen aus verschiedenen JSON-Mocks in einem Manifest wie diesem:

{ 
    "_default": [ 
    "games/someGames.json" 
    ], 
    "no-games": [ 
    "games/noGames.json" 
    ] 
} 

Sie können dann die Mock-Dateien ausschließen und die scenario-Abhängigkeit in Ihrer Produktionsanwendung entfernen.