【问题标题】:AngularJS, Jasmine: Testing a controller function calling a service using $httpAngularJS,Jasmine:测试使用 $http 调用服务的控制器函数
【发布时间】:2014-05-28 10:00:03
【问题描述】:

我正在尝试测试使用servicecontroller。但是,service 目前是null,因为我想隔离controller 中的测试。

这是当前的测试,它不起作用,因为 BoardServicenull

beforeEach(inject(function($rootScope, $controller) {

    scope = $rootScope.$new();

    BoardController = $controller('BoardController', { 
        $scope: scope,
        board: {id: 1, tasks: {}},
        BoardService: null
    });

}));


it ("should add a new task", function() {

    var tasksBefore = scope.board.tasks.length;

    scope.addTask(category, 'this is a new task');

    var tasksAfter = scope.board.tasks.length;

    expect(tasksAfter).toBe(tasksBefore + 1);
});

这是来自控制器的addTask() 函数:

$scope.addTask = function(category, task) {

    BoardService.addTask({name : task, category : category.id}).success(function(task_id) {
        // Removed code for simplicity
    });

}

最后是service中的函数:

this.addTask = function(data) {
    return $http.post($rootScope.serverRoot + '/task/create', data);            
}

【问题讨论】:

    标签: javascript angularjs unit-testing testing jasmine


    【解决方案1】:

    我认为这个想法是模拟一个BroadService...所以可能类似于...

    beforeEach(inject(function($rootScope, $controller) {
    
        scope = $rootScope.$new();
        var boardService = {
             addTask:function(task){
                var d = $q.defer();
                d.resolve(/*Whatever your service function returns: if its just a task_id, return an int or something*/);
                return d.promise;
             };
        };
    
        BoardController = $controller('BoardController', { 
            $scope: scope,
            board: {id: 1, tasks: {}},
            BoardService: boardService
        });
    
    }));
    
    
    it ("should add a new task", function() {
    
        var tasksBefore = scope.board.tasks.length;
    
        scope.addTask(category, 'this is a new task');
        scope.$apply();
        var tasksAfter = scope.board.tasks.length;
    
        expect(tasksAfter).toBe(tasksBefore + 1);
    });
    

    【讨论】:

      【解决方案2】:

      首先你需要模拟 BoardService 并存根你需要测试的函数。

      beforeEach(inject(function ($rootScope, $controller, $q) {
          fakeDashboardItemService = {
              addTask: function () {}
          };
      
          scope = $rootScope.$new();
          q = $q;
          BoardController = $controller('BoardController', {
              $scope: scope, 
              BoardService: fakeBoardService
          });
      }));
      

      然后你可以spyOn你存根的那个函数,设置你的测试用例,并返回承诺。我在这里使用 $digest 来提高速度并避免弄乱根范围 ($apply vs $digest in directive testing)

      it ("should add a new task", function() {
          spyOn(fakeBoardService, 'addTask').andCallFake(function () {
              var deferred = q.defer();
              deferred.resolve(/*return test case here*/);
              return deferred.promise;
          })
      
          var tasksBefore = scope.board.tasks.length;
          scope.addTask(category, 'this is a new task');
          scope.$digest();
          var tasksAfter = scope.board.tasks.length;
          expect(tasksAfter).toBe(tasksBefore + 1);
      });
      

      最后一个重要的变化是你应该重构你的控制器方法以使用.then而不是.success..error。这样您就可以处理完整的 $http 承诺,而不仅仅是当您从测试函数返回承诺时不会调用的成功和错误子函数。请注意,.then 接收的是整个响应,而不仅仅是数据。

      $scope.addTask = function(category, task) {
          BoardService.addTask({name: task, category: category.id}).then(function(response) {
              // handle success case
              var task_id = response.data;
          }, function(err) {
              // handle error case
          });
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-01
        • 1970-01-01
        • 2013-11-03
        • 1970-01-01
        • 1970-01-01
        • 2014-01-04
        相关资源
        最近更新 更多