그럼에도 불구하고

👨‍💻

[JavaScript] Jest란? 본문

JavaScript/JavaScript basics

[JavaScript] Jest란?

zenghyun 2023. 4. 20. 16:45

오늘은 Jest에 대해 알아보겠습니다.

 

 

[ Jest란? ]

Jest는 페이스북에서 만들어서 React와 더불어 많은 자바스크립트 개발자들로 부터 좋은 반응을 얻고 있는 테스팅 라이브러리입니다.

출시 초기에는 프런트앤드에서 주로 쓰였지만 최근에는 백앤드에서도 기존의 자바스크립트 테스팅 라이브러리를 대체하고 있습니다.

 

Jest는 라이브러리 하나만 설치하면, Test Runner와 Test Mathcher 그리고 Test Mock 프레임워크까지 제공해 주기 때문에 현재 대세라고 말할 수 있습니다.

 

[ Jest 설치 ]

// 설치
npm install jest --save-dev

 

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
  "name""js-testing-introduction",
  "version""1.0.0",
  "description""An introduction to JS testing",
  "main""./app.js",
  "scripts": {
    "start""webpack ./app.js --mode development --watch",
    "test""jest --watch"
  },
  "keywords": [
    "js",
    "javascript",
    "testing",
    "jest",
    "unit",
    "tests",
    "integration",
    "tests",
    "e2e",
    "tests"
  ],
  "author""Zenghyun",
  "license""ISC",
  "devDependencies": {
    "jest""^29.5.0",
    "puppeteer""^19.9.1",
    "webpack""^5.80.0",
    "webpack-cli""^5.0.1"
  }
}
 
cs

 

 

test 커맨드 지정하기

package.json 파일을 열고 test script 를 jest로 수정합니다.

설정을 마쳤다면 터미널에 npm test ( 혹은 yarn )를입력하면 jest 커맨드를 실행할 수 있습니다.

 

1
2
3
4
5
  "scripts": {
    "start""webpack ./app.js --mode development --watch",
    "test""jest --watch"
  }
 
cs

 

[ Jest 기본 문법 ]

먼저 test 파일을 만듭니다. test파일은 테스트할함수파일명.test.js 로 해주면 됩니다.

 

 

 

📌 파일 구조

 

- describe ( name, fn )

테스트 그룹을 묶어주는 역할을 하고, 그 안의 콜백함수 내에 테스트에 쓰일 변수, 객체들을 선언하여 일회용으로 사용할 수 있습니다.

 

- test(if) ( name, fn, timeout )

개별 테스트를 수행하는 곳으로 각 테스트를 작은 문장처럼 설명하는 역할을 합니다.

 

- expect

값을 테스트 할 때마다 주로 matcher와 함께 사용합니다.

 

- matcher 

내가 원하는 방법으로 값을 테스트하도록 사용할 수 있습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
describe('계산 테스트', () => {
   const a = 1, b = 2;
 
   test('a + b는 3이다.', () => {
      expect(a + b).toEqual(3);
   });
});
 
/*
describe('그룹 테스트 설명 문자열', () => {
   const a = 1, b = 2; // 테스트에 사용할 일회용 가짜 변수 선언
   test('개별 테스트 설명 문자열', () => {
      expect(검증대상).toXxx(기대결과);
   });
});
*/
cs

 

 

[ 예제 ]

 

 

다음 form은 이름과 나이를 입력하고 'Add User' 버튼을 누르면 아래와 같이 Zenghyun (27 years old)라는 결과를 알려줍니다.

 

 

index.html

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="styles.css">
    <title>JS Testing</title>
</head>
 
<body>
    <section class="control-panel">
        <div class="input-container">
            <label for="name">Name</label>
            <input type="text" id="name">
        </div>
        <div class="input-container">
            <label for="age">Age</label>
            <input type="number" id="age">
        </div>
        <button id="btnAddUser" class="button">Add User</button>
    </section>
    <hr>
    <section class="user-output">
        <ul class="user-list"></ul>
    </section>
    <script src="dist/main.js"></script>
</body>
 
</html>
cs

 

 

app.js

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const { checkAndGenerate, createElement } = require('./util');
 
const initApp = () => {
  // Initializes the app, registers the button click listener
  const newUserButton = document.querySelector('#btnAddUser');
  newUserButton.addEventListener('click', addUser);
};
 
const addUser = () => {
  // Fetches the user input, creates a new HTML element based on it
  // and appends the element to the DOM
  const newUserNameInput = document.querySelector('input#name');
  const newUserAgeInput = document.querySelector('input#age');
 
  const outputText = checkAndGenerate(
    newUserNameInput.value,
    newUserAgeInput.value
  );
 
  if (!outputText) {
    return;
  }
 
  const userList = document.querySelector('.user-list');
 
  const element = createElement('li', outputText, 'user-item');
  userList.appendChild(element);
};
 
// Start the app!
initApp();
 
cs

 

util.js

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const generateText = (name, age) => {
  // Returns output text
  return `${name} (${age} years old)`;
};
 
exports.createElement = (type, text, className) => {
  // Creates a new HTML element and returns it
  const newElement = document.createElement(type);
  newElement.classList.add(className);
  newElement.textContent = text;
  return newElement;
};
 
const validateInput = (text, notEmpty, isNumber) => {
  // Validate user input with two pre-defined rules
  if (!text) {
    return false;
  }
  if (notEmpty && text.trim().length === 0) {
    return false;
  }
  if (isNumber && +text === NaN) {
    return false;
  }
  return true;
};
 
exports.checkAndGenerate = (name, age) => {
  if (!validateInput(nametruefalse|| !validateInput(age, falsetrue)) {
    return false;
  }
  return generateText(name, age);
};
 
exports.generateText = generateText;
exports.validateInput = validateInput;
 
cs

 

 

💡 유닛 테스트

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 유닛 테스트
const { generateText, checkAndGenerate } = require('./util');
 
test('should output name and age', () => {
    const text = generateText('Zenghyun'27);
    expect(text).toBe('Zenghyun (27 years old)');
});
 
test('should output data-less text', () => {
    const text = generateText(''null);
    expect(text).toBe(' (null years old)');
    const text2 = generateText();
    expect(text2).toBe('undefined (undefined years old)');
});
cs

util.js에서 generateText라는 함수에 대한 테스트를 진행하고 있습니다. 

 

첫 번째 테스트는 이름과 나이를 넣었을 때 올바른 값이 나오는지에 대한 테스트입니다. 

 

두 번째 테스트는 우리의 예상 즉, 이름과 나이를 제대로 넣지 않았을 때에 대한 경우를 예측하여 올바르지 않은 값이 나오는지에 대한 테스트입니다. 

 

 

💡 통합 테스트

 

1
2
3
4
5
6
7
8
// 통합 테스트 
const { generateText, checkAndGenerate } = require('./util');
 
test('should generate a valid text output', () => {
    const text = checkAndGenerate('Zenghyun'27);
    expect(text).toBe('Zenghyun (27 years old)');
});
 
cs

 

통합 테스트에서는 하나의 함수만 사용하는 것이 아닌 checkAndGenerate와 generateText 두 개의 함수가 엮여 있을 때, 하나의 진행 과정을 통합적으로 테스트하기 위한 과정입니다.

 

 

Comments