如何在指令测试中模拟服务?

时间:2015-11-02 09:02:27

标签: angularjs unit-testing angularjs-directive

我有一个注入apiService的指令,它是$ http和其他自定义服务的包装。

当我尝试测试该指令时,我不知道如何模拟该服务:

app.directive('coreMenu', ['apiService', function (apiService) {
return {
    restrict    : 'E',
    replace     : true,
    templateUrl : 'Directives/CoreMenu.tpl.html',
    link: function (scope) {
        apiService.get({
            module: 'Core',
            route: 'Menu'
        }).then(function (response) {
            scope.menuItems = response.data;
        }, function (response) {
            // error: no menu available
        });
    }
  };
}]);

测试:

describe('coreMenu directive', function() {
var $compile, $rootScope;

beforeEach(function () {
    module('AdminTechPortal');
    module('CoreLeftMenu.tpl.html');

    inject(function (_$compile_, _$rootScope_) {
        $compile     = _$compile_;
        $rootScope   = _$rootScope_;
    });

it('replaces the element with the appropriate content', function() {
    var element = $compile("<core-menu></core-menu>")($rootScope);
    $rootScope.$digest();

    expect(element.html()).toContain('id="core-menu"');
   });
});

此测试抛出(这是正常的):

  

错误:意外请求:GET / Core / Menu /

是否可以使用$ httpbackend模拟apiService而不仅仅是xhr调用?

2 个答案:

答案 0 :(得分:1)

我在这种情况下所做的事情如下......请记住,测试承诺(这种方式)有一些工作,如果承诺需要链接,将会失败!

describe('coreMenu directive', function() {
    var $compile, $rootScope, apiServiceMock;

    // BIG WARNING:
    // This beforeEach() block MUST run before using any inject()
    beforeEach(function () {
        apiServiceMock = {};

        apiServiceMock.get = jasmine.createSpy('apiServiceMock.get').and.callFake(function() {
            return { // mock the promise
                then: function(successCb, errorCb) {
                    // keep the callbacks to call them at our convenience
                    apiServiceMock._successCb = successCb;
                    apiServiceMock._errorCb = errorCb;
                }
            };
        });

        module(function($provide) {
            // override the apiService in the DI container
            $provide.value('apiService', apiServiceMock);
        });
    });

    beforeEach(function () {
        module('AdminTechPortal');
        module('CoreLeftMenu.tpl.html');

        inject(function (_$compile_, _$rootScope_) {
            $compile     = _$compile_;
            $rootScope   = _$rootScope_;
        });
    });

    it('replaces the element with the appropriate content', function() {
        var element = $compile("<core-menu></core-menu>")($rootScope);
        $rootScope.$digest();

        // SAMPLE TESTS
        expect(apiServiceMock.get).toHaveBeenCalledWith(...);
        // test success
        apiServiceMock._successCb(...);
        expect(...) // things to expect on success
        // test failure - probably in another it()
        apiServiceMock._errorCb(...);
        expect(...) // things to expect on error
    });
});

答案 1 :(得分:0)

请按照以下步骤操作:

  1. 添加$ httpBackend变量:
  2. var $compile, $rootScope, $httpBackend;
    
    1. 在beforeEach
    2. 上注入和分配
      inject(function (_$compile_, _$rootScope_, _$httpBackend_) {
          $compile     = _$compile_;
          $rootScope   = _$rootScope_;
          $httpBackend   = _$httpBackend_;
      });
      
      1. 创建一个afterEach
      2. afterEach(function() {
            $httpBackend.verifyNoOutstandingExpectation();
            $httpBackend.verifyNoOutstandingRequest();
        });
        
        1. 测试
        2. it('replaces the element with the appropriate content', function() {
              $httpBackend.expectGET('/Core/Menu/');
              var element = $compile("<core-menu></core-menu>")($rootScope);
              $httpBackend.flush();
              $rootScope.$digest(); // Not sure if still needed
              expect(element.html()).toContain('id="core-menu"');
          });