-
[핀더펜] Vitest 적용하기개발 프로젝트: 핀더펜 2024. 6. 4. 01:10728x90
React Testing Library란?
개발자가 단위 테스트, 통합 테스트 및 구성 요소 테스트를 작성할 수 있도록 하는 테스트 프레임워크
BDD(행동 중심 개발) 및 TDD( 테스트 중심 개발 ) 를 포함한 다양한 테스트 스타일을 지원하므로 개발자가 최상의 접근 방식을 선택 가능
핵심 기능
- 확장성
- 모듈식 아키텍처를 통해 개발자는 맞춤형 플러그인 및 확장 기능을 사용하여 기능을 확장 가능
- 테스트 도구 요구 사항에 맞게 Vitest를 맞춤화하여 매우 유연하고 사용자 정의 가능한 단위 테스트 프레임워크로 만들 수 있음
- 언어 지원
- 광범위한 프로그래밍 언어를 지원
- 단일 테스트 프레임워크 내에서 다양한 언어로 작성된 코드를 테스트 가능
- Jest에서 더 쉽게 마이그레이션할 수 있도록 Jest 호환 API로 설계
- IDE 통합
- Visual Studio Code, Eclipse, IntelliJ IDEA 등 널리 사용되는 IDE( 통합 개발 환경 )와 통합되어 개발자의 생산성을 향상시킴
장점
- 속도
- HMR 및 ESBuild 번들러를 사용하여 모듈 관리를 용이하게 함
- 설정
- Vite의 구성과 플러그인을 재사용 => 최소한의 설정
- 즉시 사용 가능한 ESM, TypeScript, JSX 및 기타 최신 기능을 지원하므로 코드와 동일한 방식으로 테스트 작성 가능
- 호환성
- ES 모듈, TypeScript 및 Vite와 같은 최신 JavaScript 개발 프레임워크와 일치
- Jest의 API 지원
단점
- 문서
- 의존성
- 커뮤니티
Jest가 아닌 Vitest를 사용하는 이유
- 현재 Vite를 사용하고 있기 때문에 Jest보다 원활하게 통합할 수 있지 않을까 생각이 들었다.
- 속도적인 측면을 생각했을 때 Jest보다 Vitest가 훨씬 빠르다는 장점도 있었다.
- 또한, 테스팅 도구를 찾는 중 Jest를 사용하는 과정에서 msw 부분에 오류가 났다는 글을 읽고 Vitest를 도전하기로 했다.
설치
yarn add --dev vitest @testing-library/jest-dom @testing-library/react @testing-library/user-event msw
설정
나는 msw로 mocking api를 구현했기 때문에 test 환경에서 사용할 수 있는 mocking api server를 위한 파일을 생성해줬다.
// src/mock/server.ts import { handlers } from "./handlers.ts"; import { setupServer } from "msw/node"; export const server = setupServer(...handlers);
루트 폴더에서 vitest.setup.ts를 만든 다음 해당 설정을 추가한다.
//vitest.setup.ts import { beforeAll, afterEach, afterAll } from "vitest"; import { server } from "./src/mocks/server"; beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close());
루트 폴더에서 vitest.config.ts를 만든 다음 해당 설정을 추가한다.
//vitest.config.ts import { mergeConfig } from 'vite'; import { defineConfig } from 'vitest/config'; import viteConfig from './vite.config.ts'; export default mergeConfig( viteConfig, defineConfig({ test: { globals: true, environment: 'jsdom', setupFiles: ['./vitest.setup.ts'], }, }), );
globals: true => test 코드 작성시 describe, it, expect 등을 import 없이 사용할 수 있게 해준다.
Vitest의 경우 import가 기본적으로 필요하지만 Jest는 import없이 사용 가능하기 때문에 Jest와 동일한 방식으로 코드를 작성할 수 있도록 도와준다.package.json에 실행을 위한 코드 추가
"scripts": { "test": "vitest --ui" }
--ui => test 코드 실행 결과를 GUI 로 확인할 수 있는 사이트를 보여준다.
테스트 코드는 src 폴더에 test 폴더를 생성해서 넣어주었다. 테스트하고자 하는 파일이 Main.tsx라면 테스트 파일명을 Main.test.tsx로 해주면 된다.
실행
터미널에 다음과 같이 작성하면 테스트가 실행된다.
yarn test
실행 결과 자도으로 아래와 같은 화면이 브라우저를 통해 열리며, 해당 화면에서 실패 원인을 파악하고 코드를 수정해 다시 실행할 수 있도록 도와준다.
이 기능이 굉장히 편리하다고 느껴졌고 Vitest를 선택하기 잘했다는 생각이 들었다.
테스트 코드 작성
describe("SignUpField.tsx", () => { it("name TextField should allow letters to be inputted", () => { render(<SignUp />); const input: HTMLInputElement = screen.getByTestId("name"); fireEvent.change(input, { target: { value: "홍길동" } }); expect(input.value).toBe("홍길동"); }); )
위와 같이 test id가 name인 input 태그에 "홍길동"이라는 텍스트를 입력한 후 입력값을 확인하는 테스트 코들 작성했다.
그런데..
name TextField should allow letters to be inputted Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
이런 오류가 생겼다....
오류 원인
<SignUp> 컴포넌트 안에서 리덕스를 사용하고 있기 때문에 리덕스를 위한 Provider 태그로 컴포넌트를 감싸줘야 했다. 그런데 앞으로 모든 컴포넌트에 대해 리덕스 뿐만 아니라 라우터와 tanstack query로 적용해야 하는데 테스트 케이스마다 해당 태그를 중복해서 사용한다는 점을 해결하고 싶었다.
테스트 코드를 작성하기 위해 찾아보았던 블로그 중에서 해결 방법 아이디어를 얻을 수 있었다. (참고 블로그)
해결 방법 - custom render 함수 제작
// src/test/utils.tsx interface CustomRenderOptions { renderOptions?: RenderOptions; } export function CustomRender( ui: JSX.Element, { ...renderOptions }: CustomRenderOptions ): RenderResult { const queryClient = new QueryClient(); const Wrapper = () => { return ( <QueryClientProvider client={queryClient}> <Provider store={store}> <Routes> <Route path="/" element={ui} /> </Routes> </Provider> </QueryClientProvider> ); }; return render(Wrapper(), { ...renderOptions, wrapper: BrowserRouter, }); }
const setup = (label: string) => { const utils = CustomRender(<SignUp />, {}); const input: HTMLInputElement = screen.getByTestId(label); return { input, ...utils, }; }; describe("SignUpField.tsx", () => { it("name TextField should allow letters to be inputted", () => { const { input } = setup("name"); fireEvent.change(input, { target: { value: "홍길동" } }); expect(input.value).toBe("홍길동"); }); );
결과
이제 계속해서 테스트 코드를 작성하면 될 것 같다.
728x90'개발 프로젝트: 핀더펜' 카테고리의 다른 글
[에러] Error: EPERM: operation not permitted, unlink '...' (0) 2024.11.05 [핀더펜] Cloudfront 대체 도메인 (0) 2024.07.11 [핀더펜] 이미지 스프라이트 적용 (1) 2024.06.03 [핀더펜] 성능 최적화 마지막 (0) 2024.05.14 [핀더펜] 성능 최적화 (0) 2024.05.04 - 확장성