【问题标题】:How to test $scope.$watch properly with Jasmine in AngularJS如何在 AngularJS 中使用 Jasmine 正确测试 $scope.$watch
【发布时间】:2016-12-23 13:43:41
【问题描述】:

我是 AngularJS 和单元测试的新手,
我正在测试一个按所选类别更改的列表。
测试通过了,但前提是我使用 httpBackend.expectGET(),它期望来自“getSomethingElse”方法的 XMLHttpRequest。
我也尝试使用 scope.$digest() 但我得到了相同的结果......

控制者:

app.controller('mainCtrl', ['$scope', 'myService', function($scope, 
myService) {
  $scope.category = null;

  myService.getSomethingElse().then(function(res) {
    $scope.somethingElse = res.data;
  });

  $scope.$watch('category', function() {
    if ($scope.category !== null) {
      myService.getListByCat($scope.category.name).then(function(res) {
        $scope.list = res.data;
      });
    }
    else {
      myService.getLongList().then(function(res) {
        $scope.list = res.data;
      });
    }
  });
}]);

服务:

app.service('myService', ['$http', function($http) {
  this.getListByCat = function(category) {
    return $http.get('getting-list?cat=' + category);
  };

  this.getLongList = function() {
    return $http.get('getting-long-list');
  };

  this.getSomethingElse = function() {
    return $http.get('getting-something-else');
  };
}]);

测试

describe('Testing mainCtrl', function() {
  var scope, ctrl;

  var myServiceMock = { 
    getSomethingElse: jasmine.createSpy().and.returnValue(1),
    getListByCat: jasmine.createSpy().and.returnValue(2)
  };

  beforeEach(function() {
    module('app');
    inject(function($rootScope, $controller) {
      scope = $rootScope.$new();
      ctrl = $controller('mainCtrl', {
        $scope: scope,
        myService: myServiceMock
      });

    });
  });

  it('should update the list by selected category', function() {
    expect(scope.category).toBeNull();
    expect(scope.list).toBeUndefined();

    scope.category = {
      id: 1,
      name: 'Jobs'
    };

    scope.$apply();

    expect(myServiceMock.getSomethingElse).toHaveBeenCalled();
    expect(myServiceMock.getListByCat).toHaveBeenCalled();
  });
});

【问题讨论】:

  • 单元测试一个一个的测试单元,这样我们就知道哪一个坏了。应该有两个测试。一个人用模拟的 httpBackend 响应测试 myService。另一个使用模拟的 myService 测试控制器。顺便说一句,在基于 Promise 的方法中接受回调不是一个好习惯。更可靠的方法是返回一个承诺。
  • 感谢您的建议,我更改了服务方法以返回承诺。关于测试,你能给我举个例子来说明你将如何编写这些测试吗?我应该从返回承诺的方法中得到什么?我应该如何使用模拟服务测试控制器?
  • 这是这种分离的一个例子,我想它非常接近你的情况。 stackoverflow.com/a/39023684/3731501
  • 我根据您的示例编辑了测试。现在我收到此错误“未定义不是对象(正在评估'myService.getSomethingElse')”
  • 我做错了什么?

标签: angularjs unit-testing jasmine


【解决方案1】:

测试通过了,但前提是我使用 httpBackend.expectGET(),它期望来自“getSomethingElse”方法的 XMLHttpRequest。

这是因为您的myServiceMock 没有替换原来的myService。您有多种测试方法 - 下面给出了其中一种方法。在这里,我们将 myService 替换为服务模拟:-

beforeEach(function() {
    module('app');
    module(function($provide){
    $provide.factory('myServiceMock', 
        function(){
           return myServiceMock;
        );
    });
    inject(function($rootScope, $controller) {
      scope = $rootScope.$new();
      ctrl = $controller('mainCtrl', {
        $scope: scope,
        myService: myServiceMock
      });

    });
  });

【讨论】:

    【解决方案2】:

    你可以像这样添加你的观察者。

    $scope.categoryWatcher = categoryWatcher;
    $scope.$watch('category', categoryWatcher);
    
    function categoryWatcher() {
    if ($scope.category !== null) {
        myService.getListByCat($scope.category.name).then(function(res) {
          $scope.list = res.data;
        });
      }
      else {
        myService.getLongList().then(function(res) {
          $scope.list = res.data;
        });
      }
    }
    

    在单元测试中,只需为该处理程序创建新的 it 构造

    it('should test categoryWatcher for null value', function(){
      $scope.category = null;
      $scope.categoryWatcher();
      // your expectations
    });
    
    it('should test categoryWatcher for "desiredValue" value', function(){
      $scope.category = "desiredValue";
      $scope.categoryWatcher();
      // your expectations
    });
    

    这样,if&else 子句将在测试中使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-14
      • 2013-02-13
      • 1970-01-01
      • 2014-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-26
      相关资源
      最近更新 更多