React Hooks를 테스트하는 방법

후크를 사용하면 자체 파일에 작성할 수 있습니다. 그리고 당신은 그들을 테스트할 수 있습니다.

후크 테스트가 필요한 이유



테스트는 답이 아니지만 변경으로부터 코드를 보호하고 버그를 찾는 데 도움이 됩니다.

사용자 지정 후크에 모든 논리가 포함된 디스플레이 구성 요소가 있는 경우 사용자 지정 후크를 테스트하는 것이 좋습니다.

모든 사양을 갖추고 있지만 설계 방법을 모른다면 TDD를 사용하는 것이 좋습니다.

요컨대, "해결 방법을 모르겠습니다"라고 말하고 숨기는 것은 개발자(및 다른 사람들)에게 나쁜 습관입니다.

테스트 후크가 처음에는 작동하지 않는 이유



후크로 첫 번째 테스트를 수행했을 때 아무 것도 작동하지 않습니다. 반응 답변:

Hooks can only be called inside the body of a function component.



후크의 규칙이므로 테스트하려면 후크 주변에 무언가가 필요합니다.

운이 좋은 날입니다 , Testing Library 가 우리를 위해 this project 만들었습니다.

React 후크를 테스트하기 위한 내 스택



이 게시물에서 사용하는 예제의 경우 Typescript를 사용하지만 Javascript도 유사하게 유지됩니다.

Jest를 Enzyme과 함께 사용합니다. 저는 처음부터 이 스택으로 작업하므로 보관합니다. Typescript의 경우 ts-jest를 사용해야 합니다.

Moxios를 사용하여 Axios로 만든 API 호출을 테스트합니다.

하나 이상의 API 호출이 있는 테스트 훅은 머리가 아팠지만 사건을 해결하고 나니 머릿속이 불꽃 같았다.

후크의 경우 React Hooks Testing Library를 사용합니다. 그들은 좋은 문서를 가지고 있습니다.

시작할 시간이야



첫 번째 예는 React 문서의 사용자 지정 후크인 usePrevious입니다.

이 후크는 클래스 구성 요소의 prevProps 또는 prevState와 같은 이전 값을 저장합니다.

import { useEffect, useRef } from "react";

function usePrevious(value: any) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

export default usePrevious;


보시다시피 값에 대해 모든 유형을 사용합니다. Typescript에서는 좋은 습관이 아닙니다.

반복 개발을 사용할 때 그렇게 합니다. 시작으로 any를 사용하고 더 나은 유형으로 세분화한 후에 사용합니다. 따라서 이 사용자 지정 후크는 완료되지 않았습니다.

다른 게시물의 주제가 될 수 있습니다 😉.

이제 테스트 파일입니다.

import { renderHook } from "@testing-library/react-hooks";
import usePrevious from "./usePrevious";

import "../../setupTests";

describe("Test usePrevious hook", () => {
  const setUp = () =>
    renderHook(({ state }) => usePrevious(state), {
      initialProps: { state: 0 },
    });

  it("should return undefined on initial render", () => {
    const { result } = setUp();

    expect(result.current).toBeUndefined();
  });

  it("should always return previous state after each update", () => {
    const { result, rerender } = setUp();

    rerender({ state: 2 });
    expect(result.current).toBe(0);

    rerender({ state: 4 });
    expect(result.current).toBe(2);

    rerender({ state: 6 });
    expect(result.current).toBe(4);
  });
});


먼저 설정 기능을 정의합니다. 초기 속성으로 정수를 제공하고 0을 선택합니다.

첫 번째 경우: 초기 렌더링. 결과에는 후크의 반환이 포함됩니다. 값을 주장하거나 메서드에 액세스하는 데 사용합니다.

두 번째 경우: rerender를 사용합니다. 이 경우 각 렌더링에 대한 변수 결과를 테스트하는 것이 유용합니다.

Axios의 또 다른 예



이제 API 호출로 사용자 지정 후크를 테스트할 수 있습니다.

const useRequestWithComment = ({
  element,
  request,
  updatedStatus,
  commentAdded,
}: UseRequestWithCommentProps): [
  boolean,
  React.Dispatch<React.SetStateAction<boolean>>,
  React.Dispatch<React.SetStateAction<string | undefined>>,
] => {
  const [comment, setComment] = useState<string | undefined>();
  const [isUpdating, setUpdating] = useState<boolean>(false);

  const { t } = useTranslation();

  const { dispatch } = useContext(Context);

  useEffect(() => {
    let isCancelled = false;
    if (isUpdating && comment) {
      DataService.requestWithComment(element, comment, request).then(
        (payload) => {
          if (payload.status === 202) {
              const updatedElement = { ...element, status: updatedStatus };
              dispatch({
                type: Types.Update,
                payload: updatedElement,
              });
            }
            NotificationService.success(t("updateWithSuccess"));
          } else {
            NotificationService.error(t("somethingWentWrong"));
          }
          if (!isCancelled) {
            setUpdating(false);
          }
        },
      );
    }
    return () => {
      isCancelled = true;
    };
  }, [ element, request, updatedStatus, dispatch, comment, isUpdating, t]);

  return [isUpdating, setUpdating, setComment];
};

export default useRequestWithComment;


테스트 파일입니다

describe("Test useRequestWithComment hook", () => {
  const dispatch = jest.fn();

  beforeEach(() => {
    moxios.install(requestService);
  });

  afterEach(() => {
    moxios.uninstall(requestService);
    jest.resetAllMocks();
  });

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const wrapper = ({ children }: any) => (
    <I18nextProvider i18n={i18n}>
      <Context.Provider value={{ state: initialState, dispatch }}>
        {children}
      </Context.Provider>
    </I18nextProvider>
  );

  const setUp = () =>
    renderHook(
      ({ element, request, updatedStatus }) =>
        useRequestWithComment({ element, request, updatedStatus }),
      {
        wrapper,
        initialProps: {
          element: example,
          request: RequestWithCommentType.Dispute,
          updatedStatus: Status.Rejected,
        },
      },
    );

  it("useRequestWithComment request is success", async () => {
    moxios.wait(() => {
      const request = moxios.requests.mostRecent();

      request.respondWith(mockAccepted({}));
    });

    const { result, waitForNextUpdate } = setUp();

    const setUpdating = result.current[1];
    const setComment = result.current[2];

    act(() => {
      setComment("It's a trap");
      setUpdating(true);
    });

    expect(result.current[0]).toBeTruthy();

    await waitForNextUpdate();

    expect(dispatch).toHaveBeenCalled();
    expect(result.current[0]).toBeFalsy();
  });

  it("useRequestWithComment request is failed", async () => {
    moxios.wait(() => {
      const request = moxios.requests.mostRecent();

      request.respondWith(mockError({}));
    });

    const { result, waitForNextUpdate } = setUp();

    const setUpdating = result.current[1];
    const setComment = result.current[2];

    act(() => {
      setComment("It's a trap");
      setUpdating(true);
    });

    expect(result.current[0]).toBeTruthy();

    await waitForNextUpdate();

    expect(dispatch).not.toHaveBeenCalled();
    expect(result.current[0]).toBeFalsy();
  });
});


jest.fn() 메서드는 메서드 실행을 테스트하는 데 사용됩니다.

이전과 이후에 우리는 Axios 인스턴스를 얻습니다. 이 경우에는 requestService에서 가져옵니다. Moxios에 제공합니다. 모든 모의를 재설정하는 것은 테스트에서 부작용을 피하기 위한 것입니다.

모든 관련 구성 요소를 포함하는 래퍼가 있습니다. Redux를 사용하는 경우 스토어 공급자가 될 수 있습니다. 여기에는 React 컨텍스트 API 및 번역을 위한 공급자가 포함되어 있습니다.

다음으로 소품과 래퍼가 포함된 setUp 메서드입니다.

의견에서 설명하는 첫 번째 테스트는 성공적인 요청을 위한 것입니다. Axios는 약속을 기반으로 하며 테스트는 비동기식이어야 합니다.

Moxios는 API 호출 반환을 조롱하는 데 사용됩니다. API 호출을 위한 모의 메서드 모음이 있습니다.

act는 React 테스트 유틸리티에서와 같이 작동합니다. 문서를 살펴보세요. 간단히 말해서 업데이트를 렌더링하고 수행합니다.

테스트는 메서드가 실행될 때와 Promise가 해결된 후의 두 부분으로 나뉩니다.

케이스 테스트에 실패한 이유는 무엇입니까? 오류도 테스트해야 하기 때문입니다.

지금은 선물 시간



후크에 두 개의 API 호출이 있는 경우 moxios 대기를 이 스니펫으로 바꿀 수 있습니다.

moxios.wait(() => {
  const firstRequest = moxios.requests.at(0);
  firstRequest.respondWith(mockSuccess(firstData));
  moxios.wait(() => {
    const secondRequest = moxios.requests.at(1);
    secondRequest.respondWith(mockSuccess(secondData));
  });
});


결론



테스트를 만들고 자동화하는 것은 필수입니다.

그러나 테스트는 소프트웨어 자체로 유지되어야 한다는 점을 잊지 마십시오.
코드에서 필요한 부분과 피하는 부분을 실용적으로 선택하세요.

좋은 웹페이지 즐겨찾기