如何在指令中模拟对象内部的方法

How to mock a method inside an object in a directive

给定以下指令:

这将加载一个带有 2 个按钮的简单 html 模板,以使用不同的参数调用 goTo 函数。

function simpleMenu() {
    return {
        scope: {
            state: '='
        },
        controller: Controller,
        controllerAs: 'vm',
    };
}

function Controller($scope, $state) {
        var vm = this;
        var options = optionsService.options;
        function goTo(state) {
            switch (state){
                case 'video':
                    return $state.go('app.video');
                case 'chat':
                    return $state.go('app.chat');
            }
        }

    }

我想进行测试以确保在执行 goTo 函数时调用 $state。

我的测试使用 directiveElement 来保存已编译的 angular 元素和 directiveScope 获取该元素的范围:

var directiveElem, compile, scope, directiveScope, $state;
$state = {
    go: jasmine.createSpy().and.returnValue('asd')
};
beforeEach(function() {
    bard.inject('$timeout', '$state');
    inject(function($compile, $rootScope, $httpBackend, $state) {
        compile = $compile;
        scope = $rootScope.$new();
        $state =  $state;
    });
});
beforeEach(function() {
    directiveElem = getCompiledElement();
});

function getCompiledElement() {
    var element = angular.element('<simpleMenu></simpleMenu>');
    var compiledElement = compile(element)(scope);
    scope.$digest();
    directiveScope = element.isolateScope();
    //Here is where I suposedly inject the mocked $state
    directiveScope.$state = $state;
    return compiledElement;
}
it('should increment value on click of button', function () {
    var output = directiveScope.vm.goTo('video-specialties');
    expect($state.go).toHaveBeenCalled();
});

最后一个测试是 returning:

Expected spy unknown to have been called.

$scope 似乎在 directiveScope 中获得了正确的模拟值,但是当执行 return $state.go 时,它从其他地方获取了 $state 项,也许它正在被注入通过 simpleMenu()?我怎样才能模拟这个对象来监视它?

您需要使用 _$state_ 而不是 $state 作为 beforeEach 块的参数。

改为:

inject(function($compile, $rootScope, $httpBackend, _$state_) {

这个问题的解决方案是,Bard.js 将真实对象注入到执行中,所以每次测试都会覆盖我的模拟。允许注入模拟对象的语法是:

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