【问题标题】:mock $httpBackend in angular e2e tests在角度 e2e 测试中模拟 $httpBackend
【发布时间】:2013-05-29 06:40:43
【问题描述】:

有人知道如何在角度 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();
}));

我尝试通过$injector接收$httpBackend服务:

$injector.get('$httpBackend')

但这不是在我的测试运行的 iframe 中使用的那个。

我的下一个尝试是使用 angular.scenario.dsl,这里是代码示例:

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'

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

【问题讨论】:

  • 你如何配置你的业力在你的规范中有“注入”功能?我的测试不断收到 ReferenceError

标签: angularjs mocking acceptance-testing karma-runner end-to-end


【解决方案1】:

如果您真的想在 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([...]);
});

然后,我在我的 Jenkins CI 服务器中有第一步,将 studentsApp 替换为 studentsAppDev 并在主 index.html 文件中添加对 angular-mocks.js 的引用。

【讨论】:

  • 无需设置和创建单独的应用程序来模拟 $httpBackend。我在这里描述了如何设置它,以便它可以同时用于单元和 E2E 测试:blogs.burnsidedigital.com/2013/09/…
  • 哦,这是一个很好的解决方案,Dida,谢谢你写的。下次我不得不模拟后端时,这绝对是我要研究的东西。
  • @Dida 上面的链接现在不起作用。你能简要解释一下你做了什么吗?也许作为一个新的答案。谢谢。
  • 同时,您可以使用来自 archive.org 的存档版本,位于:web.archive.org/web/20140713175521/http://…
【解决方案2】:

模拟后端是构建复杂 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 依赖项。

【讨论】:

    【解决方案3】:

    这感觉更像是单元/规范测试。一般来说,您应该在单元/规范测试中使用模拟,而不是 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);
        });
    });
    

    【讨论】:

    • 代码与问题无关 - 问题与单元测试无关,代码用于 Jasmine 单元测试。 inject 未在 e2e 测试中定义。
    猜你喜欢
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多