angular mock 的 httpBackend 如何在测试中隐式传递给 $controller 服务?

how is angular mock's httpBackend passed implicitly to the $controller service in tests?

这个规范通过了,尽管它看起来应该失败。 (代码来自 angular 和 rails 的一本书)

这是 angular 应用程序:

var app = angular.module('customers',[]);

app.controller("CustomerSearchController",
  ["$scope", "$http", function($scope, $http) {
    var page = 0;
    $scope.customers = [];
    $scope.search = function (searchTerm) {
      if (searchTerm.length < 3) {
        return;
      }
      $http.get("/customers.json",
        { "params": { "keywords": searchTerm, "page": page } }
      ).then(function(response) {
          $scope.customers = response.data;
        },function(response) {
          alert("There was a problem: " + response.status);
        }
      );
    };
  }
]);

并且,这是 Jasmine 规范:

describe("Error Handling", function () {
  var scope = null,
    controller = null,
    httpBackend = null;
  beforeEach(module("customers"));
  beforeEach(inject(function ($controller, $rootScope, $httpBackend) {
    scope = $rootScope.$new();
    httpBackend = $httpBackend;
    controller = $controller("CustomerSearchController", {
      $scope: scope
    });
  }));
  beforeEach(function () {
    httpBackend.when('GET', '/customers.json?keywords=bob&page=0').respond(500, 'Internal Server Error');
    spyOn(window, "alert");
  });
  it("alerts the user on an error", function() {
    scope.search("bob");
    httpBackend.flush();
    expect(scope.customers).toEqualData([]);
    expect(window.alert).toHaveBeenCalledWith(
      "There was a problem: 500");
    });

});

我不明白控制器是如何获得对 $httpBackend 服务的访问权限的,该服务被注入到传递给 beforeEach 方法注入的匿名函数中。传入了 $scope 服务,但没有传入 httpBackend。

$controller 不依赖于 $httpBackend 服务,$httpBackend 未传递给它。

$http depends on $httpBackend (hence the name). $httpBackend is overridden in ngMock with mocked implementation and used by $http instead of the original $httpBackend(不适合直接使用)。

在您的代码中:

app.controller("CustomerSearchController",
  ["$scope", "$http", function($scope, $http) {
     ...
   }]
)

您要求 angular 将文件中的 $http 注入您的控制器。您没有在此处提供本地覆盖

controller = $controller("CustomerSearchController", {
      $scope: scope
    });

所以Angular用它所拥有的满足你的注入请求。正如@estus 所说,ngMock 中提供的覆盖本身注入了 $httpBackend,您已在测试中将其配置为以某种方式运行..