GitHub

[vitest]TDD + svelteKIT 유닛테스트를 해보자

hojun lee · 08/25/2023
커버이미지

⚡️vite를 쓴다면 vitest로⚡️

webpack 기반의 reactunitTest를 하기 위해선 jest가 국룰이었다. 그렇다면 viteESbuild되어 있는 sveltKIT에서는 기본 내장 TDD toolvitest를 써보자.

단위 테스트(unit test) 소프트웨어 설계의 최소 단위인 모듈이나 컴포넌트에 초점을 맞춰 테스트하는 것


TDD : test driven development

멋진 말로 테스트 주도 개발 (비슷한 것으로 JDD가 있다.)

테스트를 먼저 깔아보고 그 테스트케이스가 성공할 때까지 코드를 작성하는 개발 방식이다.

즉 기능을 실제로 구현하기 전에 테스트 케이스를 작성하고 모든 것을 테스트하여 매우 높은 수준의 품질을 유지하게 한다. 개발 중인 코드와 작동 방식을 명확하게 파악할 수 있다. 사실 백엔드 로직을 짜는데 더 많이 활용되지만, 비슷한 기술로 프론트엔드에도 잘 적용할 수 있다.

Three stage of TDD cycle

  1. 😡Red : Write test & fail
  2. 🤢Green : Write the minimum code to make it pass
  3. 🙌🏾Refactor : 깨끗한게 리팩토링해서 탄탄 코드를 만든다.

Vitest : 그저빛유닛테스터

Vitest는 vite 환경에서 사용할 수 있는 Unit Testing 프레임워크이며, jest를 경험한 적이 있다면, 유사한 함수로 테스트를 진행할 수 있기 때문에 접근성이 좋으며, svelte에는 기본으로 내장되어있을 정도로 필수 지식이 되어가고 있다. (jest랑 비슷함)

svelteKIT with vitest

% npm create svelte@latest vitest-sveltekit npm을 통해 svelte를 설치하면 vitest를 사용할 것인지 물어본다. 그 때 YES를 누르자. (유퀴즈 느낌으로다가)

create-svelte version

Welcome to SvelteKit!

✔ Which Svelte app template? › Skeleton project
✔ Add type checking with TypeScript? › Yes, using JavaScript with JSDoc comments
✔ Add ESLint for code linting? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
✔ Add Playwright for browser testing? … No / Yes
_**✔ Add Vitest for unit testing? … No / YES**_ 🤏🏽여기 

Your project is ready!
✔ Type-checked JavaScript
  https://www.typescriptlang.org/tsconfig#checkJs
✔ Vitest
  https://vitest.dev

Install community-maintained integrations:
  https://github.com/svelte-add/svelte-adders

Next steps:
  1: cd vitest-sveltekit
  2: npm install (or pnpm install, etc)
  3: git init && git add -A && git commit -m "Initial commit" (optional)
  4: npm run dev -- --open

To close the dev server, hit Ctrl-C

Stuck? Visit us at https://svelte.dev/chat

이게 설치가 완료되었으니, 실행해본다.

cd vitest-sveltekit // folder로 들어가기
npm install // 기본 패키지 설치하기
code . // vscode로 실행하기

package.JSON에 들어가 vitest가 설치된 것을 확인한다. svelteKIT의 재밌는 사실은 react처럼 dependencies와 devDependencies가 나눠져 있지않고, devDependencies만 있는 것을 볼 수 있다. 그래도 모두 개발모드로 라이브러리가 설치된다.

//package.JSON

  "scripts": {
    ...,
    "test:unit": "vitest"
  },

npm run test:unit : 테스트돌리기

터미널에서 npm run test:unit 을 입력한다.

 % npm run test:unit

> vitest-sveltekit@0.0.1 test:unit
> vitest


 DEV  v0.25.8 /Users/mac/Desktop/vitest-sveltekit

 ✓ src/index.test.js (1)

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  22:00:00
   Duration  1.01s (transform 409ms, setup 0ms, collect 16ms, tests 3ms)


 PASS  Waiting for file changes...
       press h to show help, press q to quit

뭐하나가 돌아가는것을 볼 수 있다. pass 라니 기분 좋다. 스벨트가 기본적으로 테스트코드를 하나 넣어주었다.

// index.test.ts
import { describe, it, expect } from 'vitest';

describe('sum test', () => {
  it('adds 1 + 2 to equal 3', () => {
    expect(1 + 2).toBe(3);
  });
});

필수 설치 TDD 라이브러리 설치(아마도)

우리는 각 routes 안에 있는 주소 별로 +page.svelte 파일을 이용해 테스트를 진행한다.

npm install --save-dev @testing-library/svelte
npm install --save-dev @testing-library/jest-dom jsdom
  1. @testing-library/svelte
  2. @testing-library/jest-dom

    NOTE: jest-dom adds handy assertions to Jest and it is recommended, but not required. 엥 갑자기 jest를 쓴다고 할 수 있지만, jest-dom의 어썰션 기능을 쓰는걸 권장한다. 근데 필수는 아님.

  3. jsdom

세가지 라이브러리의 도움을 받아 진행한다. component render 등의 dom test를 위해 필요하다!

vite.config.ts update

test 에 environment와 globals를 추가한다.

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';

export default defineConfig({
  plugins: [sveltekit()],
  test: {
    include: ['src/**/*.{test,spec}.{js,ts}'],
    environment: 'jsdom',
    globals: true,
  },
});

test code 작성해보기

<script>
    let name = 'world';

    let buttonText = 'Button';
    const handleClick = () => {
        buttonText = 'Button Click';
    };
</script>

<h1>Welcome to SvelteKit! {name}</h1>
<button on:click={handleClick}>{buttonText}</button>

test01

경로 : src/test/example.test.ts 컴포넌트 테스트를 위해 테스트 폴더를 만들고 멋진 작명의.test.ts(or js) 파일을 만든다.

//example.test.ts
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/svelte';
import Home from '../routes/+page.svelte';

it('renders Welcome text', () => {
  render(Home, {name: hojun);
  const Element = screen.getByText(/Welcome to SvelteKit hojun/);
  expect(Element).toBeInTheDocument();
});

간단한 테스트를 작성한다. 테스트를 작성하기 위해선 또 공부를 해야하는데, dom에 접근하는 쿼리를 이해해야한다. 필요할때마다 검색해서 쓰는게 나을 것 같다.

간단히 공부 겸 설명하자면 it 이 것을 test 해볼 건데, render 함수를 통해 Home component를 rendering한다. mount 된 것과 같은 상황을 연출할 수 있다.

screen query는 document body에 접근 할 수 있는데, getByText Query를 통해 text를 가져올 수 있다. query API 는 대부분 textMatch를 사용해 인자를 받는다.

//testing-library/svelte getByText link 이렇게 하면 주어진 TextMatch와 일치하는 textContent를 가진 텍스트 노드가 있는 모든 요소를 검색합니다.

//jest-dom ToBeInTheDocument() link This allows you to assert whether an element is present in the document or not.

test2

버튼 클릭 시 바뀌는 text값을 확인하는 것이다.

redzone : 'Button Click' 라는 fail 값 주기

// HOME component
    const handleClick = () => {
        buttonText = 'Button Click';
    };

//example.test.ts
test('button text', async () => {
    render(HOME, { name: 'World' });
    const button = screen.getByRole('button');
    await fireEvent.click(button);

    expect(button.innerHTML).toBe('Button Clicked');
});

테스트가 실패하는 것을 볼 수 있다.

// HOME component
    const handleClick = () => {
        buttonText = 'Button Clicked';
    };

(사실 테스트를 수정하는게 아니라 컴포넌트 문서를 수정해야한다^^)

이렇게 간단하게 테스트를 진행해보았다.

결론

사실 테스트를 왜 하냐 라는 생각을 엄청나게 심각하게 무지 미치도록으로 많이하게 된다. 당연 개발에 소요되는 시간을 테스트 작성에 사용할 수 밖에 없다. 하지만 장기적으로 봤을 때 컴포넌트 기획일 수도 있고, 유지보수에 탁월할 수 밖에 없다. 절대적으로 큰 기능위주로 테스트 케이스를 만들고 코드를 작성하는 습관을 들여야겠다.

참고자료