单元测试带有注入服务的Angular指令

时间:2015-12-22 17:40:05

标签: angularjs unit-testing angularjs-directive

我如何对这个指令进行单元测试,该指令将$ http调用到MyService?我如何正确地模仿或监视MyService

  angular.module('example')
    .directive('myDirective', ['MyService', function(MyService) {
      return {
        restrict: 'E',
        replace: true,
        templateUrl: 'templates/myDirective.html',
        scope: {
          name: '@',
          required: '='
        },
        link: function(scope, el, attrs, billingCtrl) {
          scope.data = [];

          MyService.get()
            .then(function(res) {
              scope.data = res;
            });
        }
      };
    }]);

我的测试:

  describe('Directive: <my-directive>', function() {
    // setup code
    beforeEach(module('example'));

    var element;
    var compile;
    var scope;
    var compiledElementScope;
    var validTemplate = '<my-directive ng-model="testModel" name="test"></my-directive>';
    var MyService = { get: function() {} };
    var $q;

    function getCompiledElement(template) {
      var compiledElement;

      compiledElement = compile(template || validTemplate)(scope);
      scope.$digest();

      return compiledElement;
    }

    beforeEach(function() {
      module(function($provide) {
        $provide.value('MyService', MyService);
      });

      inject(function($compile, $rootScope, _$q_) {
        compile = $compile;
        scope = $rootScope.$new();
        $q = _$q_;
      });

    });

    describe('my directive', function() {
      var element;

      beforeEach(function() {
        element = getCompiledElement(validTemplate);
      });

      it('should make a call to MyService and update scope.data', function() {
        // how do I asset the following
        expect(scope.data).toEqual(...);
      });
    })
  });

2 个答案:

答案 0 :(得分:1)

而不是编写var MyService = { get: function() {} };而不是在beforeEach内部创建一个间谍对象,您将模拟服务应用于提供程序。

这样的事情应该有效:     var MyService;

beforeEach(function() {
  MyService = jasmine.createSpyObj('MyService', ['get']);

  MyService.get = jasmine.createSpy('get').and.callFake(function () {
        return {
            then: function (callback) {
                callback(<RETURN_DATA>);
                return this;
            }
        };
    });

  module(function($provide) {
    $provide.value('MyService', MyService);
  });

  ... 

});

对于<RETURN_DATA>,只需将您希望保存的模拟结果返回到scope.data

答案 1 :(得分:0)

您必须使用ng-mock的$ httpBackend服务。

此服务允许您预测要发出的http请求并模拟响应。

如果未提出请求,则测试失败。

$ httpBackend.when ...这表示如果发出了http请求,则响应如下......没有期望,因此如果没有请求,则测试不会失败。

$ httpBackend.flush()表示现在发出任何待处理的请求。如果没有待处理的请求,它将失败。

别忘了......

afterEach(function () {
  httpBackend.verifyNoOutstandingExpectation();
  httpBackend.verifyNoOutstandingRequest();
});

最后,如果动态请求HTML文件,$ httpBackend会抱怨。为了避免这种情况,请预先加载karma.conf.js中的所有HTML文件

    preprocessors: {
      'src/**/!(*spec)*.js': ['coverage'],
      'dest/**/*.html': ['ng-html2js']
    },
    ngHtml2JsPreprocessor: {
      stripPrefix: 'dest/',
      moduleName: 'ngHtmlFiles'
    },
    coverageReporter: {
      type: 'html',
      dir: 'coverage'
    },
    files: [
      'dest/vendor.min.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'src/**/*.js',
      'dest/**/*.html'
    ]

我知道这个配置设置很痛苦但是如果你想遵循行业惯例那么你需要让它工作:)

相关问题