如何为依赖于工厂服务的控制器编写单元测试,而工厂服务本身又依赖于 $http 服务

How to write unit test for a controller that depends on a factory service which itself depends on the $http service

我很难理解如何使用 Jasmine 和 Karma 对一个简单的应用程序 AngularJS 进行单元测试。我试过谷歌搜索,但我自己的代码没有取得任何进展。特别是围绕模拟和注入依赖于内置 $http 服务的工厂服务。

此外,对控制器和工厂服务进行单元测试是一种很好的做法,或者其中之一就足够了。

我已将代码上传到 plunkr,如有任何帮助,我将不胜感激

https://plnkr.co/edit/WBpJ7gUZrNm8LwnCOsnR

factory.main.js

angular.module('hwApp').factory('mainFactory', ['$http', function($http){
  return {
     getData: function(){
       return $http.get('https://jsonplaceholder.typicode.com/posts/1');
     }
  }
}]);

controller.main.js

angular.module('hwApp').controller('MainCtrl', ['mainFactory', function(mainFactory){
  vm = this;
  mainFactory.getData().then(function(res){
    vm.httpData = res.data;
  })
}]);

index.html

<!DOCTYPE html>
<html ng-app="hwApp">

  <head>
    <script data-require="angular.js@1.5.0" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
    <script src="factory.main.js"></script>
    <script src="controller.main.js"></script>
  </head>

  <body ng-controller="MainCtrl as vm">
    <h1>{{vm.httpData.title}}</h1>
  </body>
</html>

通常,您会分别对控制器和服务进行单元测试。 Pluralsight 有一个很棒的课程,介绍如何使用 ngMock 对控制器和服务进行单元测试。我建议找一些可以引导您完成它的教程,但我可以为您提供一个示例,说明您在测试工厂时需要什么。

对您的工厂进行单元测试

describe("your backend service", function () {
  var dataWeWantToGet = [ "put", "your", "data", "here" ]; 
  var mainFactory;
  var $httpBackend;

  beforeEach(angular.mock.module("hwApp"));

  beforeEach(inject(function (_mainFactory_, _$httpBackend_) {
    mainFactory = _mainFactory_;
    $httpBackend = _$httpBackend_;
  }));


  it("should return movie search data from the title", function() {
    var response = [];

    $httpBackend.when('GET', 'https://jsonplaceholder.typicode.com/posts/1')
      .respond(200, dataWeWantToGet);

    mainFactory.getData()
      .then(function onSuccess(data) {
        response = data;
      });

    $httpBackend.flush();

    expect(response.data).toEqual(dataWeWantToGet);
  }); // end it

}); // end describe

在这个例子中,我们模拟了后端和控制器中发生的代码。这种隔离对于证明您的工厂独立于您的控制器工作是必要的。

控制器呢?

在测试您的控制器时,您希望实现类似的隔离,但我认为您是否需要费心通过控制器仅测试服务的功能是值得商榷的。你实际上就是这样做的。要对 控制器的那一部分进行单元测试,您必须注入您刚刚测试过的服务并以您刚刚测试过的方式使用它 在你工厂的单元测试中。

这就是测试多少和测试什么的问题开始引起争议的地方?就个人而言,我不知道我是否愿意测试控制器中使用的服务。我会测试受它影响的那些东西是否正确更新。在 Angular 中,这通常是更大的挑战。我很想听听其他人的意见。