在单元测试中模拟 $mdSideNav

Mocking $mdSideNav in unit test

我有一个足够简单的函数来关闭我的应用程序中的 $mdSidenav 实例

function closeSideNav() {
    $mdSidenav('left').close();
}

我现在需要对此进行单元测试,但在编写对 $mdSidenav 的 close() 调用的期望时遇到了问题。

我考虑过在我的测试规范中使用 $provide

module(function($provide) {
    $provide.value('$mdSidenav', function(id) {
        return {
            close: jasmine.createSpy('$mdSidenav.close')
        }
    })
});

beforeEach(inject(function(_$controller_, _$mdSidenav_) {
    $controller = _$controller_;
    $mdSidenav = _$mdSidenav_;
}));

beforeEach(function() {
    vm = $controller('NavbarController', {
        $mdSidenav: $mdSidenav
    });
});

describe('vm.closeSideNav', function() {
    beforeEach(function() {
        spyOn($mdSidenav, 'close');
        vm.closeSideNav()
    });
    it('should call $mdSidenav.close()', function() {
        expect($mdSidenav.close).toHaveBeenCalled();
    });
});

这会引发一些错误:

Error: close() method does not exist

Error: Expected a spy, but got undefined.

有没有人设法模拟 $mdSidenav 并给我一些指导?

谢谢

更新

根据建议的答案,我现在已将测试规范更新为

'use strict';
describe('NavbarController', function() {
  var $controller,
    vm,
    $mdSidenav,
    sideNavCloseMock;
  beforeEach(function() {
    module('app.layout');
    sideNavCloseMock = jasmine.createSpy();
    module(function($provide) {
      $provide.value('$mdSidenav', function() {
        return function(sideNavId) {
          return {close: sideNavCloseMock}
        }
      })
    });

  });
  beforeEach(inject(function(_$controller_, _$mdSidenav_) {
    $controller = _$controller_;
    $mdSidenav = _$mdSidenav_;
  }));

  beforeEach(function() {
    vm = $controller('NavbarController', {
      $mdSidenav: $mdSidenav
    });
  });
  describe('vm.closeSideNav', function() {
    beforeEach(function() {
      vm.closeSideNav()
    });
    it('should call $mdSidenav.close()', function() {
      expect(sideNavCloseMock).toHaveBeenCalled();
    });
  });
});

为了进行完整性检查,我的实际控制器如下所示:

(function () {
  'use strict';

  angular
    .module('app.layout')
    .controller('NavbarController', Controller);

  Controller.$inject = ['$mdSidenav'];

  function Controller($mdSidenav) {
    var vm = this;
    vm.closeSideNav = closeSideNav;

    //This only affects the sideNav when its not locked into position, so only on small\medium screens
    function closeSideNav() {
      $mdSidenav('left').close();
    }
  }
})();

不幸的是,这对我仍然不起作用,我最终遇到了一个不同的错误

TypeError: undefined is not a constructor (evaluating '$mdSidenav('left').close())

关闭方法不属于 $mdSidenav。 $mdSidenav 是一个 return 侧边导航对象的函数。这就是它抱怨 'close() method does not exist'.

的原因

你可以做的是将 $mdSidenav 模拟为 return 对象帽子模拟了 close 方法,就像这样:-

var sideNavCloseMock;
beforeEach(module(function($provide){
    sideNavCloseMock = jasmine.createSpy();
    $provide.factory('$mdSidenav', function() {
        return function(sideNavId){
            return {close: sideNavCloseMock};
        };
    });
}));

然后做

it('should call $mdSidenav.close()', function() {
    expect(sideNavCloseMock).toHaveBeenCalled();
});