我试图在Protractor测试中模拟对API调用的响应.在不同的测试中(以及在测试中),应用程序将POST到具有不同数据的API(始终是相同的URL),并期望不同的响应.
具体来说,它是一个搜索引擎,我发送不同的查询并期待不同的结果.我让它像下面的代码一样成功运行,但它变得无法管理:
var httpBackendMock = function() { angular.module('httpBackendMock',['ngMockE2E']) .run(function($httpBackend) { $httpBackend.whenPOST('//search_endpoint').respond(function(method,url,query,headers) { query = JSON.parse(query); if (query.bla = 'foo') { var results = {... lots of json ...}; } else if (query.bla = 'bar') { var results = {... lots of json ...}; } else if (query.something.else != 'whatever') { var results = {... lots of json ...}; ... etc ... } else { var results = {... lots of json ...}; } return [200,results]; }); $httpBackend.whenGET(/.*/).passThrough(); }) }; beforeEach(function(){ browser.addMockModule('httpBackendMock',httpBackendMock); });
我想做的是在一个单独的模拟中得到每个可能的响应,然后删除beforeEach并在需要时添加模拟,如下所示:
it('paginates',function(){ // mocking a search with 13 results,showing 10 results per page browser.addMockModule('search_results',<some function>); $('#searchBox').sendKeys('some keyword search'); $('#searchbutton').click(); expect($('#results li').count()).toEqual(10); browser.clearMockModules(); browser.addMockModule('search_results_page2',<some other function>); $('#next').click(); expect($('#results li').count()).toEqual(3) });
这有两个问题.
1)它不起作用.清除并添加第二个模拟后,getRegisteredMockModules()仅显示第二个模拟,但是当使用带有ChromeDriver的browser.pause()时,基于预期和手动检查,似乎第一个模拟仍然被使用.似乎你不能在没有重新加载页面的情况下改变模拟.
2)即使它确实有效,每个模拟模块都有大量的重复代码,因为它必须设置所有内容,包括passThrough().
更好的是,如果我可以将我想要的响应传递给我添加的模拟,但是我尝试了,并且在angular.module范围内没有传递给我自己的函数的任何东西.我能想到的唯一方法就是创建另一个带有提供程序的角度模块,该提供程序具有单个变量,可以跟踪所需的响应,并将其注入模拟模块.我还没有尝试过,但它似乎是一个不必要的复杂解决方案.
解决方法
量角器中的模拟模块基本上是在每次完整页面刷新时执行到浏览器中的代码.这是一种机制,可以帮助您省去自己这样做的麻烦,因为这样的刷新可以完全清除浏览器的状态(当然除了cookie).正如您已经发现的那样,直到您触发这样的刷新(使用browser.get()),您的模块永远不会被执行.如果需要,可以使用browser.executeScript()手动执行此操作.
关于嘲笑你的后端所造成的混乱 – 我采取了以下方法:
为后端设置一个默认的模拟实现,同时使其易于覆盖并在每次测试之前使用init函数注册它:
嘲笑,后端,base.js
exports.httpBackendMockBase = function () { var exposeBackendCalls = function ($httpBackend) { this.getLoginAuthenticated = $httpBackend.whenGET(/login\/authenticated.*/); this.getFindStuff = $httpBackend.whenGET(/lookup\/findStuff.*/); this.getFullProfile = $httpBackend.whenGET(/api\/full.*/); }; angular.module('httpBackendMockBase',['myClientApp','ngMockE2E']) .service('httpBackendMockBase',exposeBackendCalls) .run(function (httpBackendMockBase,testFixture) { httpBackendMockBase.getLoginAuthenticated.respond(function () { return [200,null,{}]; }); httpBackendMockBase.getFindStuff.respond(function () { return [200,{ stuff: testFixture.stuff },{}]; }); httpBackendMockBase.getFullProfile.respond(function () { return [200,{ profile: testFixture.fullProfile },{}]; }); }); };
如果你需要在某些时候重写部分,请注册一个新的模拟模块.在afterEach块中删除它:
嘲笑-于后端的特殊user.js的
exports.httpBackendMock = function() { angular.module('httpBackendMockSpecialUser',[]).run(function (httpBackendMockBase,testFixture) { httpBackendMockBase.getLoginAuthenticated.respond(function() { return [200,testFixture.specialUser,{}]; }); }); };
testFixture来自另一个保存我们数据的模块,并在mocked-backend-base之前注册:
fixture.js
exports.data = { stuff: null,fullProfile: {},specialUser: {} }; exports.module = function (data) { angular.module('backendFixture',[]).constant('testFixture',data); };
init函数:
var fixtureModule = require('fixture'); var baseMockedBackend = require('mocked-backend-base'); browser.addMockModule('backendFixture',fixtureModule.module,fixtureModule.data); browser.addMockModule('httpBackendMockBase',baseMockedBackend.httpBackendMockBase);