Jest 사용법

오준상·2020년 11월 7일
3
post-thumbnail

🙇‍♂️ 서론 🙇‍♂️

이 글은 프론트엔드 개발을 1년밖에 안한 주니어개발자가 되고싶은 고등학생이 쓴 글로 맞지 않는 정보가 있을 수 있습니다. 틀린 정보나 수정해야할 부분이 있으면 댓글로 알려주시면 정말 감사드리겠습니다. ㅜㅠㅜㅠ

🤡 jest 사용법 🤡

Base

expect(테스트 대상).Matcher(테스트 대상이 통과해야할 조건);

Jest - getting start

Matcher

matcher는 테스트 대상이 어떤 조건을 통과하는지 검사하기 위한 메소드 입니다.
matcher에는 여러가지 종류가 있습니다. 몇가지 사용법을 명세하고 나머지는 jest 공식문서를 보면 자세히 나와 있습니다.

toBe

테스트할 대상이 조건으로 제시한 값과 같다면 test를 통과시키는 메소드.
Object.is를 이용해서 같은지 다른지 비교하기 때문에, 참조타입의 값들은 비교하기 힘듭니다.

describe('toBe', () => {
	expect((() => 10)()).toBe(10); // 통과
})

toEqual

toBe와 비슷하지만, 테스트 대상이 참조타입이면, 내부 값이 같기만 하면 테스트를 통과시켜주는 메소드. 대중적으로 많이 사용합니다.

describe('toEqual', () => {
	expect({isPass: true}).toEqual({isPass: true}); // 통과
})

toBeNull, toBeUndefined, toBeDefined, toBeTruthy, toBeFalsy

말 그대로 null인가 undefined인가 defined된 값인가 truthy한 값인가 falsy한 값인가를 테스트 하는 메소드

describe('data matchers', () => {
	expect(null).toBeNull(); // 통과
  	expect(undefined).toBeUndefined(); // 통과
  	expect(10).toBeDefiend(); // 통과
  	expect(false).toBeFalsy(); // 통과
  	expect(0).toBeFalsy(); // 통과
	expect(null).toBeFalsy(); // 통과
  	expect(true).toBeFalsy(); // 통과
  	expect(1).toBeFalsy(); // 통과
})

toMatch

테스트할 대상이 정규표현식에 매칭되는지 값이 있으면 테스트를 통과하는 메소드

describe('toMatch', () => {
	expect('hello world').toMatch('hello'); // 통과
})

toContain

테스트할 대상이 배열 또는 iterable 일때, 조건에 맞는 요소가 있으면 테스트를 통과하는 메소드

describe('toContain', () => {
	expect([1,2,3]).toContain(1); // 통과
})

원하는 matcher가 없어요 ㅠㅜ

다른 matcher 찾기 (jest 공홈)

SetUp And TearDown

테스트를 실행하기 이전에 실행해야 할 코드들이 있고 테스트를 실행하고 나서 끝날 때 실행해야 하는 코드들이 있을 것입니다. 하지만 기존에 알고있던 것들로는 이런것들을 진짜로 테스트 하기 전에 코드를 넣어주거나 테스트 끝나고 코드를 실행시켜야 하는 번거로움이 있습니다. 하지만 이제 그럴 필요 없다. beforeEachafterEach가 있기 때문입니다.

beforeEach(() => {
	setDataBaseThreeElement();
});
afterEach(()=> {
	clearDataBase();
});
describe('데이터베이스 확인', ()=> {
	expect(getDataBase()).toHaveLength(3);
});
describe('데이터베이스 요소 확인', ()=> {
	expect(getDataBase()[0]).toEqual('테스트요소1');
});

// 만약 beforeEach와 afterEach가 없었다면?

describe('데이터베이스 확인', ()=> {
	setDataBaseThreeElement();
	expect(getDataBase()).toHaveLength(3);
	clearDataBase();
});
describe('데이터베이스 요소 확인', ()=> {
	setDataBaseThreeElement();
	expect(getDataBase()[0]).toEqual('테스트요소1');
	clearDataBase();
});

scoping

위처럼 처음에 세팅하고 끝날때 실행해야 하는 코드는 함수마다 다를것입니다.
이 때, 비슷한 함수끼리 묶어서 scoping을 해줄 수 있습니다
예제는 jest 예제를 가져오겠습니다.

describe('matching cities to foods', () => {
  beforeEach(() => {
    return initializeFoodDatabase();
  });

  it('Vienna <3 sausage', () => {
    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  });

  it('San Juan <3 plantains', () => {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});

다음과 같이 묶어서 테스트를 작성하면 beforeEach의 범위가 스코프로 줄어든다. afterEach도 똑같습니다.

관련 자료 - jest 공홈

Mock

mock...test 코드를 작성하면서 가장 이해가 안가는 부분이였습니다. (사실 지금도 헷갈립니다.)

어떤 함수를 테스트 해야하는데, 그 함수가 서버 요청같이 오프라인 상황에서는 실행될 수 없는 것을 요구하거나, 라이브러리를 사용하는 함수를 테스트 할 때 mocking으로 테스트 합니다. 그리고 콜백을 받을 때, mock function을 넘겨주어 테스트 하기도 합니다.

const mockFunction = jest.fn(); // mock 함수를 생성합니다.

const mockFunction2 = jest.fn(x => x); // 매개변수로 mock 함수가 리턴할 값을 넣어줍니다.

우리는 mock 함수를 callback에다가 넣었을 경우에, 그 함수가 어떤 매개변수를 받았고, 몇번 실행 되었는지를 이용하여 테스트 할 수 있습니다. jest 공홈의 예제를 가져 오겠습니다.

function forEach(items, callback) {
  for (let index = 0; index < items.length; index++) {
    callback(items[index]);
  }
}

const mockCallback = jest.fn(x => 42 + x);
forEach([0, 1], mockCallback);

expect(mockCallback.mock.calls.length).toBe(2);
// calls는 함수가 호출되었을 때 정보를 담고 있습니다. length로 몇번 호출 되었는지 가져옵니다.
expect(mockCallback.mock.calls[0][0]).toBe(0);
// 0번째 인덱스, 즉 1번째 호출의 0번째 인덱스, 1번째 매개변수를 가져옵니다.
expect(mockCallback.mock.calls[1][0]).toBe(1);
// 위와 비슷합니다.
expect(mockCallback.mock.results[0].value).toBe(42);
// result는 함수의 return값을 가져옵니다. 0번째 인덱스, 즉 1번째 결과값을 가져옵니다.

다음과 같이 mock 함수의 값에 직접 접근할 수도 있지만, 다양한 메소드들로 테스트를 할 수도 있습니다.

이왕이면 다 정리하고 싶었지만, 너무 많아서 공식 홈페이지로 대체합니다.

callback함수로 mock 함수를 넘기는 방법은 알아봤으니, 라이브러리를 쓰거나 다른 함수에 의존성을 가지는 함수들을 mocking 하는 방법을 알아봅시다.

우선 어떤 함수를 테스트 하는데, 그 함수가 사용하는 라이브러리 이름이나 의존하는 함수가 있는 주소를 알아야 합니다. 그리고는 Import를 한 후에 밑과 같이 작성합니다.

jest.mock('라이브러리 명이나 파일 주소');

다음과 같이 작성하였다면, 그 라이브러리에서 import 해온 함수는 mock 함수가 되고, 테스트 하는 함수에서도 mock 함수로 작동합니다.
그래서 mockFunc.mockReturnValue()mockFunc.mockReturnValueOnce() 같은 것들로 리턴 값을 정해주거나,
promise를 리턴하는 함수라면, resolve 때의 값과 reject때의 값을 정하는 mockFn.mockResolvedValue(value), mockFn.mockRejectedValue(value) 같은 것들로 테스트를 할 수 있습니다.

test('test', async () => {
  	const asyncMock = jest.fn().mockResolvedValue(43);

  	await asyncMock(); // 43
  
  	const mock = jest.fn();
  
	mock.mockReturnValue(42);
  
  	mock(); // 42
});

Mock Implementations

위에서 봤던 mock 함수는 리턴값이나 reject, resovle 값을 정해줄 수만 있었습니다.
하지만 mock 함수를 구현하여 사용할 수도 있습니다.

const myMockFn = jest.fn().mockImplementationOnce(cb => cb(10))

다음과 같이 mockFn.mockImplementation() 이나 mockFn.mockImplementationOnce() 를 이용하여 mock 함수를 구현할 수 있습니다.

마무리

jest를 처음 정리해 보았는데, jest의 mock 관련 함수가 타라이브러리에 비해서 매우 강력하다고 생각이 들었습니다.
다른 라이브러리에서 이런 기능을 본적이 없지만 매우 유용한 경우가 많았던 것 같습니다.

profile
만들고싶은걸만듭니다

0개의 댓글