8

有没有人有一个想法如何嘲笑角e2e测试$ httpBackend? 这个想法是在travis-ci上运行测试时对XHR请求进行存根操作。 我正在使用karma代理Travis上运行的rails应用程序中的资产和部分。 我想做没有真正的数据库查询验收测试。

这里是我的人缘配置文件的一部分:

... 
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/' 
}; 
... 

这里是我的规格文件的一部分:

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(); 
})); 

我试图获得$ httpBackend到$注射器服务:

$injector.get('$httpBackend') 

但是这不是在我的测试运行的iframe内部使用的。

下一个尝试,我用angular.scenario.dsl做,这里是代码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); 
    }); 
    }; 
}); 

用例:

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

这将导致以下错误:

<$httpBackend listing> has no method 'expectGET' 

所以,在这一点上,我不知道下一步。有没有人尝试过这样的事情,这种类型的茬真的有可能吗?

+0

你如何配置你的业力在你的规范中有“注入”功能?我一直在为我的测试收到ReferenceError – wakandan

回答

0

这种感觉更像是单元/规范测试。一般而言,您应该在单元/规范测试中使用模拟而不是e2e /集成测试。基本上,将e2e测试看作是一个主要集成应用程序的期望...嘲笑某些事情会挫败e2e测试的目的。事实上,我不确定karam如何将angular-mocks.js插入正在运行的应用程序。

该规范的测试可能看起来像......

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

代码与问题无关 - 问题不在于单元测试,代码是针对Jasmine单元测试的。 e2e测试中未定义'inject'。 –

7

如果你真的想要模拟出在E2E测试后端(此类测试称为场景,而规范是用于单元测试)那么这就是我在前一个项目中所做的工作。

我正在测试的应用程序被称为studentsApp。这是一个通过查询REST API来搜索学生的应用程序。我想测试应用程序而不用实际查询api。

我创建了一个名为studentsAppDev的E2E应用程序,我将studentsAppngMockE2E注入。在那里我定义了什么叫mockBackend应该期望什么和返回什么数据。以下是我studentsAppDev文件的例子:

"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([...]); 
}); 

然后,我在我的詹金斯CI服务器的第一步,以取代studentsAppstudentsAppDev,并在主index.html文件添加引用angular-mocks.js

+3

不需要设置和创建一个单独的应用程序来模拟$ httpBackend。我介绍了如何进行设置,以便它可以用于单元和E2E测试:http://blogs.burnsidedigital.com/2013/09/and-httpbackend-mock-for-all-unit-e2e- testings /。 – Dida

+0

哦,这是一个很好的解决方案迪达,谢谢你的写作。这绝对是我下次不得不嘲笑后端的时候要考虑的事情。 –

+0

@Dida上面的链接现在不工作。你能提供你做了什么的简短解释吗?也许作为一个新的答案。谢谢。 – Ena

1

嘲笑你的后端是构建一个复杂的Angular应用程序的重要一步。它允许在无需访问后端的情况下完成测试,您不需要测试两次,也不需要担心依赖关系。

Angular Multimocks是一个简单的方法来测试您的应用程序从一个API不同的反应行为。

它允许您为不同场景定义一组模拟API响应作为JSON文件。

它还允许您轻松更改场景。它通过允许 从不同的模拟文件中构建“场景”来实现。

如何将其添加到您的应用程序

添加必需的文件到您的网页后,简单地作为一个依赖添加scenario到应用程序:

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

一旦这个添加到你的应用程序你可以开始为API调用创建模拟。

比方说你的应用程序,使得下面的API调用:

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

您可以创建一个default模拟文件:

someGames.json

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

当你加载你的应用程序,调用到/games将返回200{"games": [{"name": "Legend of Zelda"}]}

现在让我们说你想为同一个API调用返回一个不同的响应,你可以通过改变URL来将应用置于不同的场景中。 ?scenario=no-games

no-games场景可以使用不同的模拟文件,可以说一个是这样的:

noGames.json

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

现在

当加载应用程序,调用/games将返回200{"games": []}

方案由各种JSON的嘲笑在这样一个清单:

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

然后,您可以排除模拟文件并去除生产应用程序中的scenario依赖项。