Jasmine spyOn匿名回调函数内的对象

时间:2015-12-02 19:17:05

标签: angularjs unit-testing jasmine karma-jasmine

我需要对controller函数saveSettings()进行单元测试,如下所示。我想测试成功时是否调用Session.setUrl()。我怎样才能做到这一点?

angular.module("test.controllers")
    .controller('LoginCtrl', function($scope, Validator, Session, Notify){

        $scope.apiUrl = "http://localhost:8080/web-server/";

        $scope.saveSettings = function () {

             Validator.validateUrl($scope.apiUrl, 
                  function (url) { // success callback function
                      Session.setUrl(url);
                  }, 
                  function (error) { // failure callback function
                      Notify.alert('' + error);
                  }
            );
        };
    });

服务定义如下:

angular.module('test.services')
  .service('Validator', function () {

      this.validateUrl = function(url, success, error) {

          if ( !url ) {

              error("URL not found!");
          } else {

               if (url.startsWith('http') && !url.startsWith('https')) {
                   url = url.replace('http', 'https');
               }
               success(url);
          }
      };
  });

在以下测试代码中(由@Etse提供),Session.setUrl()未被调用:

describe('LoginCtrl', function(){
    beforeEach(module('test.controllers');
    beforeEach(inject($controller){
        this.scope = {};
        this.controller = $controller('LoginCtrl', {$scope: this.scope});
    });

    it('should call setUrl on success', inject(function(Session){
        spyOn(Validator, 'validateUrl');
        spyOn(Session, 'setUrl');
        this.scope.saveSettings();
        expect(Validator.validateUrl).toHaveBeenCalled();
        expect(Session.setUrl).toHaveBeenCalled();
    });
})

已解决添加callThrough(),如下所示:

spyOn(Validator, "validateUrl").and.callThrough();

1 个答案:

答案 0 :(得分:1)

我假设Sessions是一个服务,因为您正在使用依赖注入来获取它?应该可以在服务上添加一个正常的间谍 - 只要你将它注入测试中也是如此。

在我的测试中,我只是设置了控制器,并在此-conext上公开了范围 - 这样我就可以在测试中访问它。

我在代码中发现了一些错误,并重写了它。

  • 我发现了一些丢失的护身符
  • $ scope未在控制器中注入
  • 添加了模块依赖项

这是一个有效的代码示例:

angular.module('test.services', [])
  .service('Session', function(){
    this.setUrl = function() {
       console.log("test");
    };
  })
  .service('Validator', function () {
      this.validateUrl = function(url, success, error) {
          if ( !url ) {
              error("URL not found!");
          } else {
               if (url.startsWith('http') && !url.startsWith('https')) {
                   url = url.replace('http', 'https');
               }
               success(url);
          }
      };
  });

angular.module("test.controllers", ['test.services'])
    .controller('LoginCtrl', function($scope, Validator, Session){
        $scope.apiUrl = "http://localhost:8080/web-server/";
        $scope.saveSettings = function () {
             Validator.validateUrl($scope.apiUrl, 
                  function (url) { // success callback function
                      Session.setUrl(url);
                  }, 
                  function (error) { // failure callback function
                      console.log("notify");
                  }
            );
        };
    });


//--- SPECS -------------------------
describe('LoginCtrl', function(){
    beforeEach(function(){
      module("test.controllers");
    });

    beforeEach(inject(function($controller){
        this.scope = {};
        this.controller = $controller('LoginCtrl', {$scope: this.scope});
    }));

    it('should call setUrl on success', inject(function(Session){
        spyOn(Session, 'setUrl');
        this.scope.saveSettings();
        expect(Session.setUrl).toHaveBeenCalled();
    }));
});
<script src="http://searls.github.io/jasmine-all/jasmine-all-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular-mocks.js"></script>