如何在量角器测试中切换httpBackendMocks

时间:2015-03-31 20:07:56

标签: angularjs mocking protractor

我试图在Protractor测试中模拟对API调用的响应。在不同的测试中(以及在测试中),应用程序将POST一个API(始终是相同的URL),其中POST不同的数据,并期待不同的响应。

具体来说,它是一个搜索引擎,我发送不同的查询并期待不同的结果。我让它像下面的代码一样成功运行,但它变得无法管理:

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()仅显示第二个模拟,但在使用expect时,基于browser.pause()和手动检查,似乎第一个模拟仍在使用使用ChromeDriver。看来你不能在不重新加载页面的情况下改变模拟。

2)即使它确实有效,每个模拟模块都有大量重复的代码,因为它必须设置所有内容,包括passThrough()

如果我可以将我想要的响应传递到我添加的模拟中,那将会更好,但是我尝试了这一点,并且在angular.module范围内无法传递到我自己的函数中的任何内容。我能想到的唯一方法就是创建另一个带有提供程序的角度模块,该提供程序具有单个变量,可以跟踪所需的响应,并将其注入模拟模块。我还没有尝试过,但这似乎是一个不必要的复杂解决方案。

1 个答案:

答案 0 :(得分:3)

量角器中的模拟模块基本上是在每次刷新页面时执行到浏览器中的代码。这是一种机制,可以帮助您省去自己这样做的麻烦,因为这样的刷新可以完全清除浏览器的状态(当然除了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);
};

初始化函数:

var fixtureModule = require('fixture');
var baseMockedBackend = require('mocked-backend-base');

browser.addMockModule('backendFixture', fixtureModule.module, fixtureModule.data);
browser.addMockModule('httpBackendMockBase', baseMockedBackend.httpBackendMockBase);