[javascript] JavaScript 단위 테스트에서 localStorage를 모의하는 방법은 무엇입니까?

조롱 할 라이브러리가 있습니까? localStorage 있습니까?

나는 대부분의 다른 자바 스크립트 조롱에 Sinon.JS 를 사용해 왔으며 정말 훌륭하다는 것을 알았습니다.

내 초기 테스트는 localStorage가 firefox (sadface)에서 할당을 거부한다는 것을 보여 주므로 아마도 이것에 대해 일종의 해킹이 필요할 것입니다.

현재 내 옵션은 다음과 같습니다.

  1. 내 모든 코드에서 사용하는 래핑 함수를 만들고 모의
  2. localStorage에 대한 일종의 (복잡 할 수 있음) 상태 관리 (테스트 전 스냅 샷 localStorage, 정리 복원 스냅 샷에서)를 만듭니다.
  3. ??????

이러한 접근 방식에 대해 어떻게 생각하고 이에 대해 더 나은 방법이 있다고 생각하십니까? 어느 쪽이든 저는 오픈 소스의 장점을 위해 github에 최종적으로 만드는 “라이브러리”를 넣을 것입니다.



답변

Jasmine으로 조롱하는 간단한 방법은 다음과 같습니다.

beforeEach(function () {
  var store = {};

  spyOn(localStorage, 'getItem').andCallFake(function (key) {
    return store[key];
  });
  spyOn(localStorage, 'setItem').andCallFake(function (key, value) {
    return store[key] = value + '';
  });
  spyOn(localStorage, 'clear').andCallFake(function () {
      store = {};
  });
});

모든 테스트에서 로컬 저장소를 모의하려면 테스트 beforeEach()의 전역 범위에서 위에 표시된 함수를 선언하십시오 (일반적인 위치는 specHelper.js 스크립트입니다).


답변

필요에 따라 전역 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();


답변

또한 개체의 생성자 함수에 종속성을 삽입하는 옵션을 고려하십시오.

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 개체에서 메서드를 교체하는 것은 분명히 신뢰할 수 없기 때문에 “dumb”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');


답변

이것이 제가하는 것입니다…

var mock = (function() {
  var store = {};
  return {
    getItem: function(key) {
      return store[key];
    },
    setItem: function(key, value) {
      store[key] = value.toString();
    },
    clear: function() {
      store = {};
    }
  };
})();

Object.defineProperty(window, 'localStorage', {
  value: mock,
});


답변

현재 솔루션은 Firefox에서 작동하지 않습니다. 이는 localStorage가 html 사양에 의해 수정 불가능한 것으로 정의되기 때문입니다. 그러나 localStorage의 프로토 타입에 직접 액세스하여이 문제를 해결할 수 있습니다.

크로스 브라우저 솔루션은 Storage.prototype예 를 들어 객체를 조롱하는 것입니다.

spyOn (localStorage, ‘setItem’) 대신 사용

spyOn(Storage.prototype, 'setItem')
spyOn(Storage.prototype, 'getItem')

bzbarskyteogeos 의 답변 에서 가져옴 https://github.com/jasmine/jasmine/issues/299


답변

조롱 할 라이브러리가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에서 할당을 거부한다는 것을 보여줍니다.

글로벌 컨텍스트에서만. 위와 같은 래퍼 기능을 사용하면 잘 작동합니다.


답변

다음은 sinon spy 및 mock을 사용한 예입니다.

// 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();