单元测试spyOn永远不会被称为角度工厂

时间:2016-05-04 12:14:46

标签: angularjs unit-testing jasmine karma-jasmine angularjs-factory

我正在尝试为角度工厂编写单元测试:

define([], function () {
    'use strict';

    var factoryName = 'UserFactory';
    var components = ['ProductFactory', '$state'];

    var factory = function (ProductFactory, $state) {

        var viewState = function(view, data) {
            if(data.access[view] === true) {
                return;
            }
            else {                
                $state.go('notAuth');
            }
        };

        return {
            viewState: viewState
        };
    };

    components.push(factory);

    return {
        name: factoryName,
        component: components
    };
});

我有以下单元测试:

define(['require', 'angular-mocks'], function (require) {
    'use strict';

    var angular = require('angular');

    describe('<-- UserFactory Spec ------>', function () {

        var scope, $httpBackend, userFactory;

        beforeEach(angular.mock.module('UserFactory'));

        beforeEach(inject(function (_$rootScope_, _UserFactory_) {
            scope = _$rootScope_.$new();
            userFactory = _UserFactory_;
            spyOn(userFactory, 'viewState').and.returnValue({firstName:'Joe',lastName:'Smith',access:'read'});
            scope.$apply();
        }));


        it('method viewState() was called', function () {
            expect(userFactory.viewState).toHaveBeenCalled();
        });
    });
});

但是我看到以下错误:

Expected spy viewState to have been called.

1 个答案:

答案 0 :(得分:3)

如果您要测试viewState函数的实现,则需要在测试中调用它。你也不需要测试它(因为源代码没有测试它)。

你不需要嘲笑它,这会破坏测试它的目的。这是因为模拟没有调用实际实现,除非你告诉它,但你不需要这里。

您的测试应该如下所示:

describe('<-- UserFactory Spec ------>', function () {

    var userFactory;
    var $state = {
        go: function(){}
    };

    beforeEach(angular.mock.module('UserFactory'));

    // Set the $state injectable to be our mocked out $state (only for this test)
    beforeEach(module(function ($provide) {
        $provide.value('$state', $state);
    }));

    beforeEach(inject(function (_UserFactory_) {
        userFactory = _UserFactory_;

        // Mock out the $state.go method
        spyOn($state, 'go'); 
    }));


    it('should redirect to the notAuth state', function () {
        // Call the method we are testing
        userFactory.viewState(/** pass in some conditions to make it call $state.go**/);
        expect($state.go).toHaveBeenCalledWith('notAuth');
    });
});

我在这里做了一些事情:

  • 删除了$ scope,你在这里不需要它。
  • 模拟$state.go function - 所以我们可以测试它被调用。
  • 被叫userFactory.viewState() - 所以我们可以测试这个功能。
  • 删除了您对viewState()的模拟 - 所以我们可以测试实际的实现。

要测试它是否正确调用此方法,您可以使用一些console.logs

var viewState = function(view, data) {
    console.log('View ', view);
    console.log('Data ', data);
    console.log(data.access[view]);
    console.log(data.access[view] === true);
    if(data.access[view] === true) {
        return;
    }
    else {                
        $state.go('notAuth');
    }
};

现在只需检查所有控制台日志是否符合预期。

P.S我无法测试此代码,因此可能不是100%,但这是一般要点。