테스트 코드 작성에 관한 좋은 글이 있어 서두체 첨부한다.
어떻게 테스트 코드를 작성해야 할까? : https://techblog.woowahan.com/17721/
https://saucelabs.com/resources/blog/vitest-vs-jest-comparison
Vite 프로젝트를 위해 제작된 테스트 프레임워크
빠르고 가벼운게 특징 + TS를 자체적으로 지원함. 기존의 jest는 JS만을 지원하고 TS를 사용하려면 따로 설정을 해줘야함. (jest보다 4배정도 빠르다고 한다.)
HMR, 스냅샷 테스트, 내장 모킹등을 지원함.
Vite 번들러와 함께 사용하는 것을 추천함. 따로 사용 할 수도 있지만, Vite와 같이 사용한다면 기본적인 여러 setting들이 자동적으로 이뤄진다.
export const add = (a: number, b: number) => a + b;
테스트 코드는 다음과 같이 작성 할 수 있다.
describe로 블록 단위의 테스트를 생성 후 test를 생성, expect 함수를 이용해 결과값을 예측한다.
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)
})
})
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' })
})
import { afterEach } from 'vitest'
afterEach(async () => {
await clearTestingData() // clear testing data after each test run
})
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()
}
})
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
});
});
vitest --update
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