javascript 使用Jasmine和JS对localStorage进行单元测试

new9mtju  于 2023-05-05  发布在  Java
关注(0)|答案(2)|浏览(128)

现在在兜圈子,希望有人能帮我澄清一些事情
我试图让我的头周围的单元测试window.localStorage,并相信我几乎在那里,我只是似乎不能访问实际的键/值对时,测试我的最后助手方法
我有以下方法

export function testSet() {
  window.localStorage.setItem('testSet', '1234');
}

export function testDeletePrefix() {
  let deleted = false;
  Object.entries(window.localStorage).forEach(([key, value]) => {
  console.log(key);
  // This logs out getItem setItem removeItem clear
  if (key.startsWith("test") && key !== "test") {
    window.localStorage.removeItem(key);
    console.log(`Item with key '${key}' deleted from local storage.`);
    deleted = true;
  }
});
  if (!deleted) {
    console.log(`No key starting with 'test' found in local storage.`);
  }
}

单元测试

setItemSpy = spyOn(window.localStorage, "setItem").and.callFake(
    (key, value) => {
      store[key] = value.toString();
    }
  );

testSet();
expect(setItemSpy).toHaveBeenCalledWith("testSet", "1234");
testDeletePrefix();

每当我运行这个测试时,我都会得到输出No key starting with 'test' found in local storage.
所以spyOn已经确认键/值对已经设置,那么为什么在循环window.localStorage时不能访问它们呢?会非常感激一些指点,这样我就能明白这一点

eh57zj3b

eh57zj3b1#

问题是.and.callFake(。我们说的是,每次你被调用,都要调用这个假的实现,而不是真实的的实现。我们需要testDeletePrefix的真实的实现来将项放在本地存储中。
尝试使用.and.callThrough()来调用实际的实现。

// !! Change this to .and.callThrough() to call the actual implementation
// every time `localStorage.setItem` is called and then the actual implementation
// of localStorage.setItem is called.
setItemSpy = spyOn(window.localStorage, "setItem").and.callThrough();

testSet();
expect(setItemSpy).toHaveBeenCalledWith("testSet", "1234");
testDeletePrefix();
bjp0bcyl

bjp0bcyl2#

我要发布一个解决方案,现在是为我工作(虽然如果有人发现的东西是不正确的,请让我知道)
我首先创建了一个mockLocalStorage助手

export const mockLocalStorage = {
  data: {},
    setItem: function(key, value) {
      this.data[key] = value;
    },
    getItem: function(key) {
      return this.data[key];
    },
    removeItem: function(key) {
      delete this.data[key];
    },
    clear: function() {
      this.data = {};
    },
    entries: function() {
      return Object.entries(this.data);
    },
  };

在我的测试规范中,我有

import { testDeletePrefix } from "../src/my_helper.js";
import { mockLocalStorage } from "./support/mockLocalStorage.js";

describe("deletePrefix", () => {

  beforeEach(() => {
    mockLocalStorage.data = {};
  });

  it("should delete a prefixed item from local storage if it exists", () => {
    // Set the item
    mockLocalStorage.setItem('test123', 'test');

    spyOn(mockLocalStorage, 'removeItem').and.callThrough();
    // Call testDeletePrefix function, passing in localStorage of choice
    testDeletePrefix(mockLocalStorage);

    // Expectations
    expect(mockLocalStorage.removeItem).toHaveBeenCalledTimes(1);
    expect(mockLocalStorage.getItem('test123')).toBeUndefined();
  });
});

最后,我更新了testDeletePrefix()方法,使其接受一个参数,即localStorage对象,因此在测试中它可以是mockLocalStorage,而在激活时用户可以传入window.localStorage

export function testDeletePrefix(localStorage) {
  let deleted = false;
  const entries = localStorage.entries ? localStorage.entries() : Object.entries(localStorage);
  entries.forEach(([key, value]) => {
    if (key.startsWith('test) && key !== 'test) {
      localStorage.removeItem(key);
      deleted = true;
    }
  });
  if (!deleted) {
    console.log(`No key starting with test followed by text found in local storage.`);
  }
}

相关问题