【问题标题】:How to switch between httpBackendMocks in protractor test如何在量角器测试中在 httpBackendMocks 之间切换
【发布时间】:2015-03-31 20:07:56
【问题描述】:

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

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

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

【问题讨论】:

    标签: angularjs mocking protractor


    【解决方案1】:

    量角器中的模拟模块基本上是在每次整页刷新时在浏览器中执行的代码。这是一种为您省去自己做这件事的麻烦的机制,因为这样的刷新会完全清除浏览器的状态(当然,cookie 除外)。正如您已经发现的那样,在您触发这样的刷新(使用browser.get())之前,您的模块永远不会执行。如果需要,您可以使用 browser.executeScript() 手动执行此操作。

    关于嘲笑你的后端所带来的混乱 - 我采取了以下方法: 为您的后端提供一个默认的模拟实现,同时使其易于覆盖并在每次测试之前使用 init 函数注册它:

    mocked-backend-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 块中删除它:

    mocked-backend-special-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);
    

    【讨论】:

    • “正如您已经发现的那样,在您触发这样的刷新(使用 browser.get())之前,您的模块永远不会执行。”谢谢!
    • 似乎每次执行 browser.get() 时,都必须事先执行另一个 browser.addMockModule,因为如果更改 URL,mock 将停止工作。
    • 不应该这样。这会破坏模拟模块的目的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 2013-02-09
    • 2018-12-17
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多