Skip to main content

Command Palette

Search for a command to run...

[ 살펴보기 ] Jest - Global APIs

Updated
6 min readView as Markdown
[ 살펴보기 ] Jest - Global APIs
C

A developer living in Busan, Korea

아래 포스트의 Jest 테스트 환경은 Vite를 통해 구성된 React project에서 진행되며 다른 환경에서의 테스트 구성은 Jest Documentation에서 확인할 수 있습니다. ( Reference - Testing Web Frameworks )

Jest package를 설치하고 ( npm install -D jest ) npm init jest@latest명령어를 실행하면 초기 설정을 위한 prompt가 나오며 prompt에 대한 답변에 따라 jest.config.js configuration 파일을 생성해 준다.

만약 jest test 환경을 jsdom으로 설정했다면 다음 package를 추가로 설치해야 한다.

npm install -D jest-environment-jsdom

테스트를 진행하기 위한 필자의 jest.config.js는 다음과 같다.

/** @type {import('jest').Config} */
const config = {
  testEnvironment: "jsdom",
};
export default config;

이제 package.json 파일에 test를 실행하기 위한 script가 추가되었는지 확인하고 추가되어 있지 않다면 다음과 같이 추가 해준다.

...
  "scripts": {
    ...
    "test": "jest"
  }
...

이제 다음과 같이 간단한 test파일을 생성해 test code를 추가해보자.

// main.test.js

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

위의 코드를 추가하고 npm run test를 실행하면 jest를 통해 작성한 test가 실행되는 것을 확인할 수 있다. test와 expect는 jest에서 제공하는 global api이므로 따로 import하지 않아도 jest를 실행하면 jest가 자동으로 global environment에 추가 해준다.

Typescript를 사용한다면 추가적인 설정이 필요하다. Jest가 typescirpt file을 compile할 수 있도록 다음 package를 설치하고 configuration에 추가해준다.

npm install -D ts-jest @types/jest

jest.config.js

/** @type {import('jest').Config} */
const config = {
  testEnvironment: "jsdom",
  transform: {
    "^.+.tsx?$": ["ts-jest", {}],
  },
};

export default config;

추가로 test file이 typescript라면 jest global apis를 사용할 때 type 오류가 발생할 것이다. type 오류를 해결하기 위해선 다음과 같이 @jest/globals를 추가로 설치에서 global api를 직접 import해서 사용할 수 있다.

npm install -D @jest/globals
// main.test.ts

import { expect, test } from "@jest/globals";

test("adds 1 + 2 to equal 3", () => {
  expect(1 + 2).toBe(3);
});

또는 @types/jest package를 설치하고 기존과 같이 별도의 import 없이 사용할 수 있다.

npm install --D @types/jest
// main.test.ts

test("adds 1 + 2 to equal 3", () => {
  expect(1 + 2).toBe(3);
});

이제 Jest에서 제공하는 Globals api 중 일부를 살펴보자. 모든 api list는 다음 documentation에서 확인할 수 있다 ( Reference - Jest - Globals )

test

Test를 실행할 code의 이름과 내용을 선언한다. 예를 들어 다음은 expect function에 전달되는 함수의 결과를 테스트하는 간단한 test code다.

test("adds 1 + 2 to equal 3", () => {
  expect(1 + 2).toBe(3);
});

expect

실제로 테스트할 연산을 전달하고 연산의 결과를 검사하는 matcher를 추가해 최종 결과를 검사할 수 있다. 아래의 예제에선 expect에 전달한 function의 연산 결과가 7일 때 정상이므로 toBe matcher를 통해 해당 사항을 설정해주고 있다.

const sum = (firstNum: number, secondNum: number) => firstNum + secondNum;

test("test sum function", () => {
  expect(sum(2, 5)).toBe(7);
});

test.each

하나의 Test block에서 Test 값을 여러가지 설정하여 결과를 테스트할 때 사용할 수 있다.

test.each([
  { a: 1, b: 1, expected: 2 },
  { a: 1, b: 2, expected: 3 },
  { a: 2, b: 3, expected: 5 },
])("test sum function - current : ($a, $b)", ({ a, b, expected }) => {
  expect(sum(a, b)).toBe(expected);
});

Test.each api interace는 다음과 같다.

 test.each(table)(name, fn, timeout)

table parameter에 테스트할 값과 예상 결과값을 전달하고 name 부분은 test의 name을 설정한다. 위의 예제와 같이 전달하는 variable을 $variable_name 형식으로 사용할 수 있다. 그리고 fn에는 실행될 test code를 선언하고 timeout은 optinal 값으로서 각각의 test가 실행될 수 있는 최대 시간을 설정할 수 있다. default는 5 seconds로 설정되어 있다.

위의 테스트를 실행하면 결과는 아래와 같다.

 PASS  __test__/main.test.ts
  √ test sum function - current : (1, 1)
  √ test sum function - current : (1, 2)                                                                
  √ test sum function - current : (2, 3)

test.only, test.skip

test.only 또는 test.skip을 통해 test code 중 특정 test가 실행하거나 특정 test를 skip할 수 있다. 다음과 같이 test 파일에 test.only를 사용하는 test code가 있으면 해당 파일에선 test.only가 적용된 test를 제외하고 모든 test가 skip 된다.

// skip 된다.
test("test sum function", () => {
  expect(sum(2, 5)).toBe(7);
});

// test가 실행된다.
test.only("test substract function", () => {
  expect(subtract(5, 2)).toBe(3);
});

반면 skip을 통해 특정 test code만 test실행 시 제외할 수 있다.

// test가 실행된다.
test("test sum function", () => {
  expect(sum(2, 5)).toBe(7);
});

// skip 된다.
test.skip("test substract function", () => {
  expect(subtract(5, 2)).toBe(3);
});

describe

관련된 여러 test를 group화 할 때 사용할 수 있다. 예를 들어 두 수를 빼는 substract function을 위한 test를 모아서 group화 한다고 가정해보자.

const subtract = (firstNum: number, secondNum: number) => firstNum - secondNum;

describe("test subtract behavior", () => {
  test("test subtrack", () => {
    expect(subtract(5, 2)).toBe(3);
  });
  test("test subtrack - should not to be lower than 0", () => {
    expect(subtract(2, 5)).toBeGreaterThanOrEqual(0);
  });
});

위의 예제에서 두 번째 테스트에서 결과 값이 0이거나 0보다 큰 수이길 기대하지만 결과는 -3이 나오므로 위의 테스트는 실패한다.

describe.each

Describe역시 test.each와 같이 하나의 describe block에서 여러 테스트 값을 테스트 하고 싶을 때 describe.each를 사용할 수 있다. 만약 두 숫자를 뺀 값을 반환하는 함수를 테스트 하고 두 숫자를 뺀 값이 0보다 작을 때는 0을 반환하게끔 function이 구성되어 있다고 가정해보자.

describe each를 통해 다음과 같이 각 테스트 값과 결과 값에 따라 각자 테스트를 진행할 수 있다.

describe.each([
  { a: 5, b: 2, expected: 3 },
  { a: 2, b: 5, expected: 0 },
])("test subtract behavior : current - ($a, $b)", ({ a, b, expected }) => {
  test("test subtrack", () => {
    expect(subtract(a, b)).toBe(expected);
  });
  test("test subtrack - should not to be lower than 0", () => {
    expect(subtract(a, b)).toBeGreaterThanOrEqual(expected);
  });
});

위의 코드를 실행하면 결과는 다음과 같다.

PASS  __test__/main.test.ts
  test subtract behavior : current - (5, 2)
    √ test subtrack                                                                              
    √ test subtrack - should not to be lower than 0 (1 ms)                                              
  test subtract behavior : current - (2, 5)                                                             
    √ test subtrack                                                                                     
    √ test subtrack - should not to be lower than 0                                                     

Test Suites: 1 passed, 1 total                                                                          
Tests:       4 passed, 4 total

afterAll

Afterall에 function을 전달하면 현재 test file의 test 실행이 모두 종료되고 나서 전달한 function이 실행된다. function은 test 성공, 실패여부와 무관하게 실행된다.

afterAll(() => {
  console.log(" all test completed  ");
});

test("test sum function", () => {
  expect(sum(2, 5)).toBe(7);
});

test("test substract function", () => {
  expect(subtract(5, 2)).toBe(3);
});

afterEach

현재 test file의 각각의 test의 실행이 종료되고 나서 실행된다. 즉, 아래의 경우에는 test가 두 개 이므로 AfterEach로 전달한 function이 두 번 실행된다. test의 성공, 실패 여부와 무관하게 실행된다.

afterEach(() => {
  console.log(" after each test ");
});

test("test sum function", () => {
  expect(sum(2, 5)).toBe(7);
});

test("test substract function", () => {
  expect(subtract(5, 2)).toBe(3);
});

beforeAll

현재 test file의 test code가 실행되기 전에 실행되는 function을 전달할 수 있다.

beforeAll(() => {
  console.log(" before all test ");
});

test("test sum function", () => {
  expect(sum(2, 5)).toBe(7);
});

test("test substract function", () => {
  expect(subtract(5, 2)).toBe(3);
});

beforeEach

현재 test file에 선언된 각 test code가 실행되기 전에 실행되는 function을 전달할 수 있다.


beforeEach(() => {
  console.log(" before each test ");
});

test("test sum function", () => {
  expect(sum(2, 5)).toBe(7);
});

test("test substract function", () => {
  expect(subtract(5, 2)).toBe(3);
});

More from this blog

[ 살펴보기 ] TypeORM - Transactions, Migration

Transation Database 종류에 따라 detail한 부분은 차이점이 조금씩 있겠지만 각 sql statement는 개별적인 transaction block을 통해 실행되며 Database 설정에 따라 sql statement의 실행 결과가 자동으로 commit되어 영구히 적용되거나 commit을 직접 실행하기 전까지는 영구히 적용되지 않을 수 있다. 대부분의 경우 default로 sql statement 실행 결과가 자동으로 comm...

Feb 9, 20256 min read
[ 살펴보기 ] TypeORM - Transactions, Migration

Dev Diary

184 posts