业力:模块化请求测试的麻烦

Karma: trouble modularizing testing of requests

这是我正在测试的控制器:

angular
  .module('mean-starter')
  .controller('AdminController', AdminController);

function AdminController(User, Auth, $state) {
  var vm = this;
  User
    .list()
    .success(function(data) {
      vm.users = data;
    })
    .error(function() {
      console.log('Problem getting users.');
    });

  vm.delete = function(id) {
    User
      .delete(id)
      .success(function(data) {
        if (Auth.getCurrentUser()._id === id) Auth.logout(); // deleting yourself
        else $state.reload();
      })
      .error(function() {
        console.log('Problem deleting user.');
      });
  };
}

我的测试:

describe('AdminController', function() {
  var createController, scope, $httpBackend;

  beforeEach(module('mean-starter'));
  beforeEach(module('templates'));
  beforeEach(inject(function($controller, $rootScope, _$httpBackend_) {
    $httpBackend = _$httpBackend_;
    scope = $rootScope.$new();
    createController = function() {
      return $controller('AdminController');
    }
  }));

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  it('gets users', function() {
    var users = [ 'user1', 'user2', 'user3' ];
    $httpBackend
      .expectGET('/users')
      .respond(users);
    var adminController = createController();
    $httpBackend.flush();
    expect(adminController.users).toEqual(users);
  });

  it('has a method that deletes users', function() {
    $httpBackend.expectDELETE('/users/1').respond();
    $httpBackend.expectGET('/current-user').respond();
    $httpBackend.expectGET('/logout').respond();
    var adminController = createController();
    adminController.delete(1);
    $httpBackend.flush();
  });
});

当前失败:

它要我在第二个 it 块中有一个 $httpBackend.expectGET('/users')。我不想那样做。对我来说,如果每个 it 块测试一个单独的东西,它似乎更加模块化和有条理。


1) 我该怎么办?

2) 为什么我会收到 $digest already in progress 错误?

  1. 你是对的,每个 it 应该测试一个单独的东西。 it 块是单独的测试,它们不(不应该)相互依赖。第二个测试创建一个新的控制器实例,它会尝试立即加载用户。即使您对这里的这个请求不感兴趣,您仍然需要设置处理它的 mock。您也可以使用 .when(...).respond(...) 形式代替 expect.

编辑: 一种使它更好的方法是将 GET 的模拟移动到 beforeEach 作为 $httpBackend.expectGET('/users').respond(users)。这样,第一个 GET 的模拟将适用于所有 it 测试,因此在测试其他内容时,您无需担心。至于第一个it,也许只做expect(adminController.users).toEqual(users)就够了。 (对于控制器如何获取用户没有明确的期望,只有值——但这显然来自 GET,因此覆盖范围基本相同。)

  1. 会不会是这样的:https://github.com/angular/angular.js/pull/6522 ?