jest
특징
- facebook 에서 만듦
- testing library가 아닌 testing framework
- 보통 testing 시 test runner, test matcher, test mock 이 필요한데 이것을 하나의 framework으로 구현한것
- testing 대상
- test.js 로 끝나는 파일명
- __test__ 디렉터리 내의 파일
기본 패턴
test("테스트 설명", () => {
expect("검증 대상").toXxx("기대 결과");
});
mathcer
- toBe
- primitive 값을 비교할때 사용됨
- toEqual
- 참조형 데이터(ex-object) 검증시 사용
- toBeTruthy / toBeFalsy
- true 또는 false로 간주되는 값 검증(ex-0, '', null...)
- 배열 관련
- toHaveLengh - 배열 길이 체크
- toContain - 특정 원소가 배열에 있는지 검증
- toMatch
- 정규식 기반의 테스트가 필요한 경우
- toThrow
- 예외 발생 여부 테스트
// 함수 실행 결과를 전달시 함수 실행과정에서 실제 exception 발생하여 무조건 이 테스트는 실패함
test("throw when id is non negative", () => {
expect(getUser(-1)).toThrow();
expect(getUser(-1)).toThrow("Invalid ID");
});
// 의도된 검증 가능
test("throw when id is non negative", () => {
expect(() => getUser(-1)).toThrow();
expect(() => getUser(-1)).toThrow("Invalid ID");
});
비동기 코드 테스팅
Promise
// promise 인스턴스를 반환하는 함수
function fetchData(){
return new Promise...
...
}
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
async/await
// promise 객체가 반환되는 경우 return 을 사용해야 test가 promise객체 return 후에 완료됨
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
// async await pattern
test('the data is peanut butter', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
await expect(fetchData()).rejects.toMatch('error');
});
전, 후처리
1. 각 test 에서 전, 후처리가 필요한 경우
// test 전 처리
beforeEach(() => {
initializeCityDatabase();
});
// test 후 처리
afterEach(() => {
clearCityDatabase();
});
2. test 전체에서 단 한번만 전, 후처리가 필요한경우
beforeAll(() => {
return initializeCityDatabase();
});
afterAll(() => {
return clearCityDatabase();
});
3. 하나의 test 파일에서 환경 구분이 필요한 경우
// 해당 test file 에 전처리 적용
beforeEach(() => {
return initializeCityDatabase();
});
describe('matching cities to foods', () => {
// describe block 내에서 적전처리 적용
beforeEach(() => {
return initializeFoodDatabase();
});
test(...
});
Mock function
실제 구현을 지우고,
함수에 대한 호출 및 매개변수를 캡쳐
new로 인스턴스화 할때 생성자 함수의 인스턴스를 캡쳐,
mocking이란, 해당 코드가 의존하는 부분을 가짜로 대체하는 기법
-> mocking을 이용하면 실제 객체를 사용하는것 보다 가볍고, 빠르게 실행되면서도, 항상 동일한 결과를 내는 테스트 작성 가능
mockReturnValue
- mock 함수의 호출값은 기본적으로 undefined
- 어떤 값을 리턴할지 정해주는 함수
mockFn.mockReturnValue("I am a mock!");
console.log(mockFn()); // I am a mock!
mockResolvedValue
- resovle value를 정해주어 mock aync function 생성
mockFn.mockResolvedValue("I will be a mock!");
mockFn().then((result) => {
console.log(result); // I will be a mock!
});
mockImplementation
- 함수를 전달하여 재구현된 함수로 사용 가능
mockFn.mockImplementation((name) => `I am ${name}!`);
console.log(mockFn("Dale")); // I am Dale!
toBeCalled---
- mock 함수가 어떻게 불렸는지에 대한 정보 제공
mockFn("a");
mockFn(["b", "c"]);
expect(mockFn).toBeCalledTimes(2);
expect(mockFn).toBeCalledWith("a");
expect(mockFn).toBeCalledWith(["b", "c"]);
spyOn
- 외부 정보에 의존적인 경우(ex-api 통신) 내부에서 사용하는 함수(ex-axios.get) 에 spyOn을 붙여서 검증
const axios = require("axios");
const userService = require("./userService");
test("findOne fetches data from the API endpoint", async () => {
// spyOn 으로 특정 함수를 모니터링
const spyGet = jest.spyOn(axios, "get");
await userService.findOne(1);
expect(spyGet).toBeCalledTimes(1);
expect(spyGet).toBeCalledWith(`https://jsonplaceholder.typicode.com/users/1`);
});
하지만, 위의 경우는 api 서버와 통신이 필수이므로 network 에 의존적임
따라서, axios.get이 고정된 결과를 리턴하도록 mock 함수로 대체해주면 됨
const axios = require("axios");
const userService = require("./userService");
test("findOne returns what axios get returns", async () => {
// axios get 의 결과를 고정
axios.get = jest.fn().mockResolvedValue({
data: {
id: 1,
name: "Dale Seo",
},
});
const user = await userService.findOne(1);
expect(user).toHaveProperty("id", 1);
expect(user).toHaveProperty("name", "Dale Seo");
});
cypress
E2E test를 위한 도구
E2E, 단위테스트, 통합테스트 까지사용 가능
GUI도구 지원
스펙관리 및 디버깅이 편리
사용법
describe - it
- 테스트 블록 생성 및 테스트 함수 작성
// describe 블록 내부가 아니면 테스트 하지 않음
describe('My First Test', () => {
it('Does not do much!', () => {
expect(true).to.equal(true)
})
})
cy.visit
- 특정 url 을 브라우저로 접근
describe('empty spec', () => {
it('passes', () => {
cy.visit('https://example.cypress.io')
})
})
cy.contains
- 브라우저 내에서 포함하는 element 중 특정 내용을 포함하는 element를 찾음
describe('empty spec', () => {
it('passes', () => {
cy.visit('https://example.cypress.io')
cy.contains('type')
})
})
여러 element selector query들을 보유
참고자료
https://www.daleseo.com/jest-basic/
Jest로 기본적인 테스트 작성하기
Engineering Blog by Dale Seo
www.daleseo.com
https://jestjs.io/docs/asynchronous
Testing Asynchronous Code · Jest
It's common in JavaScript for code to run asynchronously. When you have code that runs asynchronously, Jest needs to know when the code it is testing has completed, before it can move on to another test. Jest has several ways to handle this.
jestjs.io
'Front-end' 카테고리의 다른 글
turborepo (0) | 2024.07.18 |
---|---|
Intersection Observer API (0) | 2023.07.18 |
Popover api (1) | 2023.06.13 |
컴포넌트 디자인 패턴 (2) | 2022.11.23 |