126

モックするライブラリはありますlocalStorageか?

私は、他のほとんどの JavaScript モックにSinon.JSを使用してきましたが、それが本当に優れていることがわかりました。

私の最初のテストでは、localStorage が firefox (sadface) で割り当て可能であることを拒否しているため、おそらくこれを回避するための何らかのハックが必要になるでしょう:/

現在の私のオプションは次のとおりです(私が見るように):

  1. すべてのコードで使用するラッピング関数を作成し、それらをモックします
  2. localStorage のある種の (複雑かもしれない) 状態管理 (テスト前のスナップショット localStorage、クリーンアップ復元スナップショット) を作成します。
  3. ??????

これらのアプローチについてどう思いますか? また、他にもっと良い方法があると思いますか? いずれにせよ、オープンソースの良さのために、最終的に作成した「ライブラリ」をgithubに配置します。

4

17 に答える 17

149

Jasmine でモックする簡単な方法を次に示します。

let localStore;

beforeEach(() => {
  localStore = {};

  spyOn(window.localStorage, 'getItem').and.callFake((key) =>
    key in localStore ? localStore[key] : null
  );
  spyOn(window.localStorage, 'setItem').and.callFake(
    (key, value) => (localStore[key] = value + '')
  );
  spyOn(window.localStorage, 'clear').and.callFake(() => (localStore = {}));
});

すべてのテストでローカル ストレージをモックする場合は、beforeEach()上記の関数をテストのグローバル スコープで宣言します (通常はspecHelper.jsスクリプトです)。

于 2013-01-17T15:04:18.903 に答える
57

必要に応じて、グローバルな localStorage / sessionStorage (同じ API を使用) をモックするだけです。
例えば:

 // Storage Mock
  function storageMock() {
    let storage = {};

    return {
      setItem: function(key, value) {
        storage[key] = value || '';
      },
      getItem: function(key) {
        return key in storage ? storage[key] : null;
      },
      removeItem: function(key) {
        delete storage[key];
      },
      get length() {
        return Object.keys(storage).length;
      },
      key: function(i) {
        const keys = Object.keys(storage);
        return keys[i] || null;
      }
    };
  }

そして、実際に行うことは、次のようなものです。

// mock the localStorage
window.localStorage = storageMock();
// mock the sessionStorage
window.sessionStorage = storageMock();
于 2014-10-03T11:07:36.890 に答える
23

また、オブジェクトのコンストラクター関数に依存関係を挿入するオプションも検討してください。

var SomeObject(storage) {
  this.storge = storage || window.localStorage;
  // ...
}

SomeObject.prototype.doSomeStorageRelatedStuff = function() {
  var myValue = this.storage.getItem('myKey');
  // ...
}

// In src
var myObj = new SomeObject();

// In test
var myObj = new SomeObject(mockStorage)

モッキングと単体テストに合わせて、ストレージの実装のテストは避けたいと思います。たとえば、アイテムを設定した後にストレージの長さが増加したかどうかを確認しても意味がありません。

実際の localStorage オブジェクトのメソッドを置き換えるのは明らかに信頼できないため、「ダム」な mockStorage を使用し、必要に応じて個々のメソッドを次のようにスタブします。

var mockStorage = {
  setItem: function() {},
  removeItem: function() {},
  key: function() {},
  getItem: function() {},
  removeItem: function() {},
  length: 0
};

// Then in test that needs to know if and how setItem was called
sinon.stub(mockStorage, 'setItem');
var myObj = new SomeObject(mockStorage);

myObj.doSomeStorageRelatedStuff();
expect(mockStorage.setItem).toHaveBeenCalledWith('myKey');
于 2013-11-22T20:04:37.507 に答える
6

モックするライブラリはありますlocalStorageか?

私はただ一つ書いた:

(function () {
    var localStorage = {};
    localStorage.setItem = function (key, val) {
         this[key] = val + '';
    }
    localStorage.getItem = function (key) {
        return this[key];
    }
    Object.defineProperty(localStorage, 'length', {
        get: function () { return Object.keys(this).length - 2; }
    });

    // Your tests here

})();

私の最初のテストでは、localStorage が firefox で割り当て可能であることを拒否することが示されています

グローバル コンテキストのみ。上記のラッパー関数を使用すると、問題なく動作します。

于 2012-07-14T18:34:55.257 に答える
5

それを使用する各メソッドにストレージ オブジェクトを渡す必要はありません。代わりに、ストレージ アダプタに接続する任意のモジュールに構成パラメータを使用できます。

古いモジュール

// hard to test !
export const someFunction (x) {
  window.localStorage.setItem('foo', x)
}

// hard to test !
export const anotherFunction () {
  return window.localStorage.getItem('foo')
}

構成「ラッパー」機能を備えた新しいモジュール

export default function (storage) {
  return {
    someFunction (x) {
      storage.setItem('foo', x)
    }
    anotherFunction () {
      storage.getItem('foo')
    }
  }
}

コードのテストでモジュールを使用する場合

// import mock storage adapater
const MockStorage = require('./mock-storage')

// create a new mock storage instance
const mock = new MockStorage()

// pass mock storage instance as configuration argument to your module
const myModule = require('./my-module')(mock)

// reset before each test
beforeEach(function() {
  mock.clear()
})

// your tests
it('should set foo', function() {
  myModule.someFunction('bar')
  assert.equal(mock.getItem('foo'), 'bar')
})

it('should get foo', function() {
  mock.setItem('foo', 'bar')
  assert.equal(myModule.anotherFunction(), 'bar')
})

クラスは次のMockStorageようになります

export default class MockStorage {
  constructor () {
    this.storage = new Map()
  }
  setItem (key, value) {
    this.storage.set(key, value)
  }
  getItem (key) {
    return this.storage.get(key)
  }
  removeItem (key) {
    this.storage.delete(key)
  }
  clear () {
    this.constructor()
  }
}

本番コードでモジュールを使用する場合は、代わりに実際の localStorage アダプターを渡します

const myModule = require('./my-module')(window.localStorage)
于 2016-11-07T19:03:16.993 に答える
4

sinon スパイとモックを使用した例を次に示します。

// window.localStorage.setItem
var spy = sinon.spy(window.localStorage, "setItem");

// You can use this in your assertions
spy.calledWith(aKey, aValue)

// Reset localStorage.setItem method    
spy.reset();



// window.localStorage.getItem
var stub = sinon.stub(window.localStorage, "getItem");
stub.returns(aValue);

// You can use this in your assertions
stub.calledWith(aKey)

// Reset localStorage.getItem method
stub.reset();
于 2015-03-02T14:12:36.000 に答える
0

残念ながら、テストシナリオでlocalStorageオブジェクトをモックできる唯一の方法は、テストしているコードを変更することです。コードを無名関数(とにかく実行する必要があります)でラップし、「依存性注入」を使用してウィンドウオブジェクトへの参照を渡す必要があります。何かのようなもの:

(function (window) {
   // Your code
}(window.mockWindow || window));

次に、テスト内で次を指定できます。

window.mockWindow = { localStorage: { ... } };
于 2013-03-06T21:30:10.543 に答える