Jasmine 和 angular 模拟:模拟处理本地存储的服务

Jasmine and angular mocks : mocking a service that handles local storage

我有一项名为 wd$cache 的服务,它基本上是 localStorage.setItem 和 get.item 的包装器。

现在我正在尝试测试使用该服务实现特定结果的控制器。主要问题是我有一个 IF 语句,只有当你已经设置了 localstorage 时才会触发它,这让我抓狂! (我们这里做的是TDD)

服务

(function () {

angular
    .module('hub')
    .controller('promotionNotificationCtrl', promotionNotificationCtrl);

promotionNotificationCtrl.$inject = [
    'hub$promotions',
    'hub$client',
    'wd$cache'
];

function promotionNotificationCtrl(
    hub$promotions,
    hub$client,
    wd$cache) {

    var vm = this;
    activate();

    //////////

    function activate () {

        hub$promotions.get(hub$client.brand, hub$client.subbrand).success(function (data) {

            if (!wd$cache.get('hub$notification')) {

                wd$cache.add('before', 123);
            } else {

                wd$cache.add('after', 321);
            }
        });
    }
}
})(); 

测试

describe('The promotion notification controller', function () {

var controller,
    hub$client,
    $httpBackend,
    wd$cache,
    mockData = [{

        "foo": "bar"
    },
    {
        "faa": "boo"
    }];


beforeEach(module('hub'));
beforeEach(module('wired.core'));

beforeEach(module(function ($provide) {

    hub$client = {

        brand: 'bw',
        subbrand: 'plus'
    };

    wd$cache = {

        add: function () {

        },

        get: function () {

        }
    };

    $provide.value('hub$client', hub$client);
    $provide.value('wd$cache', wd$cache);
    spyOn(wd$cache, 'add');
}));

beforeEach(inject(function ($controller, _$httpBackend_, _hub$promotions_) {

    controller = $controller('promotionNotificationCtrl');
    $httpBackend = _$httpBackend_;
    hub$promotions = _hub$promotions_;

    // request
    $httpBackend.expectGET("/umbraco/api/promotions/get/?brand=bw&lang=en&subbrand=plus").respond(200, mockData);
    $httpBackend.flush();
}));

it('should attempt to add a cache with a "before" key if no previous "hub$notification" cache was found', function () {


    expect(wd$cache.add).toHaveBeenCalledWith('before', 123); //WORKING
})

it('should attempt to add a cache with a "after" key if a previous "hub$notification" cache was found', function () {

    localStorage.setItem('hub$notification');
    wd$cache.add('hub$notification');

    expect(wd$cache.add).toHaveBeenCalledWith('after', 123); // NOT WORKING
    // CANT GET THROUGH THE IF STATEMENT
})
});

基本上,无论我做什么,我都无法在 BeforeEach 块之后到达 'Test Cases'。自从模拟它以使用实际存储以来,我已经尝试了一切。

有什么想法吗?

您可以提供一个已经填充了一些数据的模拟实现:

var cache = {};    

beforeEach(module(function ($provide) {
    // ...
    wd$cache = {
        add: function (key, value) {
            cache[key] = value;
        },
        get: function (key) {
            return cache[key];
        }
    };

    // add initial data here or in the individual tests, e.g.


    // ...
}));

要为特定测试用例正确设置缓存,您可以像这样使用 cache 字段:

cache['hub$notification'] = 'whatever value makes sense here';

当然你也可以在beforeEach中这样做。

目前您正在尝试这样做:

wd$cache.add('hub$notification');
expect(wd$cache.add).toHaveBeenCalledWith('after', 123);

这是有问题的,原因有二:

  • 您没有更新缓存,因为您在没有 .andCallThrough() 的情况下监视 add 方法。您应该修复此问题(在创建间谍后添加 .andCallThrough()),否则来自控制器的更新将不会影响缓存。

  • 间谍会记录您的通话。您不希望将此用于设置代码,因为它会使后续断言更加复杂。