LoginSignup
0
0

Vitest で localStorage の単体テストを実装する

Posted at

はじめに

この記事では、Vitest というテストフレームワークで localStorage がどのように動作をするか確認していきます。

開発環境

開発環境は以下の通りです。

  • Windows11
  • VSCode
  • TypeScript 4.9.5
  • React 18.2.0
  • Vite 4.1.5
  • Vitest 0.34.5
  • jsdom 22.1.0

テスト対象コードの実装

テストを実装する前に localStorage を利用したテスト対象となるコードを実装します。

localStorage.ts
export const BOOK_IN_RENTAL_KEY = "book-in-rental";

export const getBookInRental = () => localStorage.getItem(BOOK_IN_RENTAL_KEY);

export const setBookInRental = (book: string) =>
  localStorage.setItem(BOOK_IN_RENTAL_KEY, book);

今回はこちらの getBookInRentalsetBookInRental の単体テストの実装を通して、localStorage の動作について確認していきます。

値のテスト

まずは、シンプルに setBookInRental で設定した値を getBookInRental で取得できるかテストします。

localStorage.test.ts
describe("localStorage tests", () => {
  test("get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    setBookInRental(DUMMY_BOOK_IN_RENTAL);

    expect(getBookInRental()).toBe(DUMMY_BOOK_IN_RENTAL);
  });
});

image.png

次は、複数のテスト間での localStorage の動作を確認します。

localStorage.test.ts
describe("localStorage tests", () => {
  test("get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    setBookInRental(DUMMY_BOOK_IN_RENTAL);

    expect(getBookInRental()).toBe(DUMMY_BOOK_IN_RENTAL);
  });
  test("get a book in rental from localStorage without setting it", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    expect(getBookInRental()).toBe(DUMMY_BOOK_IN_RENTAL);
  });
});

image.png

上記の2つ目のテスト("get a book in rental from localStorage without setting it")では、値を設定していませんが、1つ目のテスト("get a book in rental from localStorage")で設定した値を取得できることが確認できます。

また、以下のようにテストごとに localStorage.clear() すれば、テスト間で値が共有されることを防ぐことができます(とあるユニットテストのデータが別のユニットテストのデータに影響を及ぼすことを防止できます)。

localStorage.test.ts
describe("localStorage tests", () => {
  afterEach(() => {
    localStorage.clear();
  });
  test("get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    setBookInRental(DUMMY_BOOK_IN_RENTAL);

    expect(getBookInRental()).toBe(DUMMY_BOOK_IN_RENTAL);
  });
  test("not get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    expect(getBookInRental()).not.toBe(DUMMY_BOOK_IN_RENTAL);
  });
});

image.png

関数が呼び出されていることのテスト

vi.spyOn を利用して getItemsetItem が呼び出されているかどうか確認します。
なお、仮想DOMとして jsdom を利用する場合、localStorage を spy on する際は、localStorage ではなく、Storage.prototype を第一引数に渡す必要があるようです。

まずは getItem が呼び出されているか確認します。

localStorage.test.ts
describe("localStorage tests", () => {
  const getItemSpy = vi.spyOn(Storage.prototype, "getItem");

  afterEach(() => {
    getItemSpy.mockClear();
    localStorage.clear();
  });
  test("get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    setBookInRental(DUMMY_BOOK_IN_RENTAL);

    expect(getBookInRental()).toBe(DUMMY_BOOK_IN_RENTAL);
    expect(getItemSpy).toHaveBeenCalledWith(BOOK_IN_RENTAL_KEY);
  });
  test("not get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    expect(getBookInRental()).not.toBe(DUMMY_BOOK_IN_RENTAL);
    expect(getItemSpy).toHaveBeenCalledWith(BOOK_IN_RENTAL_KEY);
  });
});

image.png

setItem も同じように実装して、呼び出されているかどうか確認します。

localStorage.test.ts
describe("localStorage tests", () => {
  const getItemSpy = vi.spyOn(Storage.prototype, "getItem");
  const setItemSpy = vi.spyOn(Storage.prototype, "setItem");

  afterEach(() => {
    getItemSpy.mockClear();
    setItemSpy.mockClear();
    localStorage.clear();
  });
  test("set and get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";

    setBookInRental(DUMMY_BOOK_IN_RENTAL);
    expect(setItemSpy).toHaveBeenCalledWith(
      BOOK_IN_RENTAL_KEY,
      DUMMY_BOOK_IN_RENTAL
    );

    expect(getBookInRental()).toBe(DUMMY_BOOK_IN_RENTAL);
    expect(getItemSpy).toHaveBeenCalledWith(BOOK_IN_RENTAL_KEY);
  });
  test("not get a book in rental from localStorage", () => {
    const DUMMY_BOOK_IN_RENTAL = "test book";
    expect(getBookInRental()).not.toBe(DUMMY_BOOK_IN_RENTAL);
    expect(getItemSpy).toHaveBeenCalledWith(BOOK_IN_RENTAL_KEY);
  });
});

image.png

まとめ

今回は localStorage を利用した値の入出力及び関数呼び出しの単体テストの動作を確認しました。今後は localStorage を利用した結合テストや localStorage を利用したライブラリを利用したコードのテストの動作確認もしてみたいです。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0