【问题标题】:Unit test Angular directive with injected service带有注入服务的单元测试 Angular 指令
【发布时间】:2015-12-22 17:40:05
【问题描述】:

如何对这个指令进行单元测试,该指令对MyService 进行 $http 调用?如何正确模拟或监视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(...);
      });
    })
  });

【问题讨论】:

    标签: angularjs unit-testing angularjs-directive


    【解决方案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);
      });
    
      ... 
    
    });
    

    对于&lt;RETURN_DATA&gt;,只需返回您希望保存到scope.data 中的模拟结果。

    【讨论】:

      【解决方案2】:

      你必须使用 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'
          ]
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-10
        • 2016-09-18
        • 2019-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-29
        • 1970-01-01
        相关资源
        最近更新 更多