Vitest로 test 코드 작성법

이수빈·2024년 11월 14일
0

Typescript

목록 보기
14/17
post-thumbnail

Vitest란?

https://saucelabs.com/resources/blog/vitest-vs-jest-comparison

  • Vite 프로젝트를 위해 제작된 테스트 프레임워크

  • 빠르고 가벼운게 특징 + TS를 자체적으로 지원함. 기존의 jest는 JS만을 지원하고 TS를 사용하려면 따로 설정을 해줘야함. (jest보다 4배정도 빠르다고 한다.)

  • HMR, 스냅샷 테스트, 내장 모킹등을 지원함.

  • Vite 번들러와 함께 사용하는 것을 추천함. 따로 사용 할 수도 있지만, Vite와 같이 사용한다면 기본적인 여러 setting들이 자동적으로 이뤄진다.

기본 Unit test

  • 기본적인 util 함수나 간단한 공용함수를 testing 하고자 할때 작성한다. 아래와 같은 간단한 util 함수가 있다고 가정
export const add = (a: number, b: number) => a + b;
  • 테스트 코드는 다음과 같이 작성 할 수 있다.

  • describe로 블록 단위의 테스트를 생성 후 test를 생성, expect 함수를 이용해 결과값을 예측한다.

  • https://vitest.dev/api/expect.html

  • expect 함수는 Assertion이라는 객체를 반환하는데, Vitest는 내부적으로 Assertion이란 객체를 처리하도록 설계되었기 때문에 expect 함수의 반환값이 없더라도 테스트 통과 여부를 판별 할 수 있다.

import { describe, expect, test } from 'vitest'

const person = {
  isActive: true,
  age: 32,
}

describe('person', () => {
  test('person is defined', () => {
    expect(person).toBeDefined()
  })

  test('is active', () => {
    expect(person.isActive).toBeTruthy()
  })

  test('age limit', () => {
    expect(person.age).toBeLessThanOrEqual(32)
  })
})
  • Assertion 객체의 interface는 다음과 같다. 객체 안에 함수들을 담고 있는 형태이다.
type Promisify<O> = {
    [K in keyof O]: O[K] extends (...args: infer A) => infer R ? O extends R ? Promisify<O[K]> : (...args: A) => Promise<R> : O[K];
};

type PromisifyAssertion<T> = Promisify<Assertion<T>>;

interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAssertion<T> {
    toBeTypeOf: (expected: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => void;
    toHaveBeenCalledOnce: () => void;
    toSatisfy: <E>(matcher: (value: E) => boolean, message?: string) => void;
    toHaveResolved: () => void;
    toHaveResolvedWith: <E>(value: E) => void;
    toHaveResolvedTimes: (times: number) => void;
    toHaveLastResolvedWith: <E>(value: E) => void;
    toHaveNthResolvedWith: <E>(nthCall: number, value: E) => void;
    resolves: PromisifyAssertion<T>;
    rejects: PromisifyAssertion<T>;
}
  • 테스트를 실행하기전에 혹은 실행한 후 실행 할 수 있는 function 들도 존재한다.

  • 각각의 test를 실행하기 전 beforeEach 함수가 실행된다. 이전의 mock을 지우고 전처리과정에 사용한다.

import { beforeEach } from 'vitest'

beforeEach(async () => {
  // Clear mocks and add some testing data after before each test run
  await stopMocking()
  await addUser({ name: 'John' })
})
  • 각각의 test를 실행한 후에 afterEach 함수가 실행된다.
import { afterEach } from 'vitest'

afterEach(async () => {
  await clearTestingData() // clear testing data after each test run
})
  • 테스트를 시작하기전 beforeAll 함수가 한번 실행된다. 테스트가 실행된 후 optional cleanup 또한 가지고 있다.
import { beforeAll } from 'vitest'

beforeAll(async () => {
  // called once before all tests run
  await startMocking()

  // clean up function, called once after all tests run
  return async () => {
    await stopMocking()
  }
})
  • 테스트가 다 실행된 이후 afterall 함수는 딱 한번만 실행된다.
import { afterAll } from 'vitest'

afterAll(async () => {
  await stopMocking() // this method is called after all tests run
})

스냅샷 테스트

  • 컴포넌트의 렌더링 결과를 테스트 하기 위한 기법, 특정 시점에서의 컴포넌트의 UI 출력이 예상된 형태와 일치하는지를 검증한다.

  • 처음으로 toMatchSnapshot()으로 테스트를 실행할 때 Vitest는 렌더링된 출력 또는 개체를 테스트 파일 옆의 snapshots 폴더에 스냅샷으로 저장한다.

  • 후속 test에서 Vitest는 현재 출력을 저장된 스냅샷과 비교해서 테스트 통과여부를 결정한다.

import { render } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import MyComponent from './MyComponent';

describe('Snapshot Testing', () => {
  it('matches the snapshot', () => {
    const { asFragment } = render(<MyComponent />);
    expect(asFragment()).toMatchSnapshot(); // First run creates a snapshot
  });
});
  • 다음과 같은 명령어를 이용해 직접 snapshot을 업데이트 할 수도 있다.
vitest --update

Type Test

  • vitest는 TS도 지원하기 때문에 Type을 테스팅 하는 기능도 제공한다.

  • 주로 expectTypeof 함수를 이용해 타입을 검증한다.

import { expectTypeOf } from 'vitest';

interface MyType {
  name: string;
  age: number;
}

describe('Type Testing', () => {
  it('checks the type of an object', () => {
 	expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>()
	expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 })
	expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 })
	expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>()
  });
});
  • 여기서 Matcher로 많이쓰는게 2가지인데, toEqualTypeOf, toMatchTypeOf 이다

  • toEqualTypeOf는 expectTypeOf의 type과 toEqualTypeOf의 타입이 완벽하게 같은지 검증하고,

  • toMatchTypeOf는 expectTypeOf의 type이 toMatchTypeOf로 주어진 입을 extends 하는지 여부를 나타낸다.

ref) 공식문서 : https://vitest.dev/
https://velog.io/@asdf99245/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C%EC%97%90%EC%84%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%9E%91%EC%84%B1%ED%95%B4%EB%B3%B4%EC%9E%90#%EB%8B%A8%EC%88%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8

profile
응애 나 애기 개발자

0개의 댓글