cant update jasmine spy

时间:2016-09-18 19:43:42

标签: javascript angularjs testing jasmine

Hi I have a Angular service that uses another service that loads data from the local storage on init.

angular
    .module('app')
    .factory('localStorage', function ($window)
    {
        if (!$window.localStorage)
        {
            // throw Error
        }

        return $window.localStorage;
    });

angular
    .module('app')
    .factory('session', function (localStorage)
    {
        var container = JSON.parse(localStorage.getItem('sessionContainer'));

        return {
            getUser: getUser
        };
    });

Now i want to test the session service.

    describe('SessionService', function ()
    {
        var service;
        var localStorageMock;

         // Load the module.
        beforeEach(module('appRegistration'));

        // Create mocks.
        beforeEach(function ()
        {
            logMock = {};

            localStorageMock = jasmine.createSpyObj('localStorageServiceMockSpy', ['setItem', 'getItem']);
            localStorageMock.getItem.and.returnValue('{}');

            module(function ($provide)
            {
                $provide.value('localStorage', localStorageMock);
            });

            inject(function (_session_)
            {
                service = _session_;
            });
        });

        it('should call `getItem` on the `localStorageService` service', function ()
        {
            expect(localStorageMock.getItem).toHaveBeenCalledWith('sessionContainer');
        });

        describe('getUser method', function ()
        {
            it('should return an empty object when the user is not set', function ()
            {
                var result = service.getUser();

                expect(result).toEqual({});
            });

            it('should return the user data', function ()
            {
                // localStorageMock.getItem.and.returnValue('{"user":{"some":"data"}}');

                var result = service.getUser();

                expect(result).toEqual({some: 'user data'});
            });
        });

    });

As you can see in the should return the user data section. I need a way to update the container so getUser returns the expected data.

I tried to update the getItem spy, but this does not work. The localStorageMock is already injected in the session service when i want to change the spy.

Any help?

1 个答案:

答案 0 :(得分:2)

最简单的方法是使用一个具有模拟值的变量,这对两个函数作用域都是通用的:

    var getItemValue;
    beforeEach({
      localStorage: {
        getItem: jasmine.createSpy().and.callFake(function () {
          return getItemValue;
        }),
        setItem: jasmine.createSpy()
      }
    });

    ...
        it('should return the user data', function ()
        {

            getItemValue = '{"user":{"some":"data"}}';

            inject(function (_session_) {
                service = _session_;
            });

            var result = service.getUser();

            expect(result).toEqual({some: 'user data'});
        });

请注意,对于所有规范,inject应从beforeEach移至it(不涉及getItemValue的规范可能会使用较短的语法,{{ 1}})。

这揭示了服务设计的缺陷,使其对测试不友好。

解决方案是对it('...', inject(function (session) { ... }))进行懒惰评估,因此在应用container引导后,有时间模拟它:

inject

此外,这也可以测试.factory('session', function (localStorage) { var containerCache; function getUser() { ... return this.container; } return { get container() { return (containerCache === undefined) ? (containerCache = JSON.parse(localStorage.getItem('sessionContainer'))) : containerCache; }, getUser: getUser }; }); 。在这种情况下,session.container间谍值可以在需要时重新定义。