210511 Node.js TDD Practice 다섯번째 이야기 - 통합 테스트 (Integration Test) 코드 작성

Nodejs Mocking Http Request

통합 테스트(Integration Test)

모듈을 통합하는 단계에서 수행하는 테스트로, 단위 테스트를 통해서 모듈들이 모두 잘 작동하는 것을 확인한 뒤에 모듈들을 서로 연동하여 테스트를 수행하는 것을 말한다.

Supertest

단위 테스트에서 jest 모듈을 사용해서 테스트를 했다면, 통합 테스트는 supertest라는 모듈을 이용해서 구현을 한다.

단위 테스트에서는 MongoDB 부분은 문제가 없다는 가정하에 mock 함수로 처리를 했는데 통합 테스트에서는 supertest를 사용해서 실제로 요청을 보내서 테스트를 진행한다.

통합 테스트 코드 작성

통합 테스트 코드는 실제 작성한 코드의 로직을 기반으로 작성한다.

예를들어 아래와 같이 MongoDB에 req.body를 통해 넘겨받은 데이터를 새로 추가하고 추가된 데이터를 별도의 변수에 담아 response의 status code가 201인 경우에 json 데이터로 함께 전달하고 있다.

1
2
3
4
5
6
7
8
9
exports.createProduct = async (req, res, next) => {
try {
const newProduct = await productModel.create(req.body);
console.log('createProduct', newProduct);
res.status(201).json(newProduct);
} catch (error) {
next(error);
}
};

위의 코드를 통합 테스트 코드로 작성을 하면, 아래와 같이 통합테스트 코드를 구현할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
const request = require('supertest');
const app = require('../../server');
const newProduct = require('../data/new-data.json');

test('POST /api/products', async () => {
// 실제 코드와 같이 요청을 보내고 함께 보낸 데이터를 response 변수에 담는다.
const response = await request(app).post('/api/products').send(newProduct);
// 위의 response 객체의 상태코드를 확인
expect(response.statusCode).toBe(201);
// response의 body(json) 데이터를 확인을 한다.
expect(response.body.name).toBe(newProduct.name);
expect(response.body.description).toBe(newProduct.description);
});
Read more

210510 Node.js TDD Practice 네번째 이야기 - 비동기 요청 에러에 대한 테스트 코드 작성

Nodejs Mocking Http Request

Error handling

이번 포스팅에서는 req.body로부터 넘겨받은 데이터를 MongoDB에 저장할때 발생할 수 있는 에러 케이스에 대해 에러 처리를 하기 위한 테스트 코드 작성에 대한 내용을 작성해보려고 한다.

현재 테스트에 있어서 프론트단이 별도로 개발되어있지 않기 때문에 Postman을 이용해서 임의로 만든 API를 테스트 할 것이다. Postman을 사용하면 API 개발의 생산성을 높여 줄 수 있으며, Request를 임의로 전달해서 테스트를 할 수 있다.

Postman

Postman의 사용은 위의 캡처와 같이 우선 테스트할 Request의 method를 선택을 하고, Endpoints를 작성해준다. 요청시에 Body에 별도로 데이터를 담아서 전달해야되는 경우에는 Body 옵션을 선택해서 전송하고자하는 데이터의 타입을 지정해서 데이터를 작성해주면 된다.

모든 설정이 끝난뒤에 Send버튼을 클릭해주면, 앞서 endpoint에 작성해준 URL과 mapping되는 router의 callback 함수(controller)가 앞서 Postman에서 설정한 내용을 기반으로 실행이 된다.
(Body에 별도의 데이터를 담아서 전달한 경우에는 callback 함수(controller)의 req.body를 통해 전달이 된다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.use('/api/products', productRoutes);

router.post('/', productController.createProduct);

// 비동기 요청에서 발생되는 에러에 대한 예외처리
exports.createProduct = async (req, res, next) => {
try {
const newProduct = await productModel.create(req.body);
console.log('createProduct', newProduct);
res.status(201).json(newProduct);
} catch (error) {
next(error);
}
};
Read more

210504 React TDD Practice with RTL

RTL(React Testing Library)

RTL(React-Testing-Library)는 모든 테스트를 DOM 위주로 한다. 별도로 props나 state를 조회하는 테스트는 하지 않는다. 그 이유는 컴포넌트를 리팩토릴할때 내부 구조와 네이밍은 많이 바뀔 수 있어도 실제 동작방식은 크게 바뀌지 않기 때문이다.
따라서 RTL에서는 컴포넌트의 기능이 똑같이 동작한다면, 컴포넌트의 내부 구현 방식이 바뀌어도 실패하지 않도록 테스트를 지원한다.

  • DOM 시뮬레이션은 JSDOM이라는 도구를 사용하여 document.body에 React 컴포넌트를 렌더링한다.

  • @testing-library/jest-dom 은 DOM관련 matcher를 사용할 수 있게 지원해주는 라이브러리이다.

snapshot 테스트

1
2
3
4
5
6
7
8
9
10
import { render } from '@testing-library/react';
import Profile from './Profile';

describe('<Profile /> 컴포넌트 테스트', () => {
test('snapshot 테스트',() => {
const snapshot = render(<Profile surname="lee", givenname="hyungi" />);
// container는 검사하는 컴포넌트의 최상위 DOM을 가르킨다.
expect(snapshot.container).toMatchSnapshot();
});
});
Read more

210402 Node.js TDD Practice 세 번째 이야기

beforeEach, response status code and value, mockReturnValue(), _isEndCalled(), _getJSONData()

Nodejs Mocking Http Request

beforeEach() 활용해서 공통 코드 처리하기

여러개의 테스트 코드를 작성하면서 공통된 코드가 있다면 beforeEach 안에 작성을 해서 불필요한 코드의 반복을 줄여줄 수 있다.
beforeEach의 위치는 describe의 내부와 외부 모두 가능하다. describe 단위로 공통된 코드는 describe 내부에 beforeEach를 작성해서 공통된 코드를 처리해주고, 모든 describe에 공통적으로 참조해야하는 공통 코드가 있다면 이는 describe 외부에 작성을 해서 작성한 모든 테스트 케이스에서 공통 코드를 참조할 수 있도록 해야한다.
(아래 첨부한 첫 번째 노트를 참고)

response 객체를 통해 상태값 전달하기

request 객체의 body 속성으로부터 저장할 데이터에 대한 정보를 받아 데이터베이스에 저장을 했다면 이제 제대로 저장이 되었는지, 제대로 저장이 되었다면 상태값에 대한 정보를 보내줘야 한다.
상태값은 res.status(201)과 같이 response 객체의 status로 상태코드를 인수로 넘겨준다.

테스트 코드에서는 mock response 객체의 statusCode 속성을 참고해서 전달된 상태값을 확인할 수 있다.
expect(res.statusCode).toBe(201)

response 객체를 통해 결과값 전달하기

앞서 response 객체의 status로 상태코드를 인수로 넘겨서 상태값을 전달하였다.
그렇다면 추가적으로 결과값을 전달해야될 때에는 어떻게 해야할까?
(아래 첨부한 세 번째 노트 필기 참고)

Read more

210309 TDD study for React

요 몇일동안 아니 저번달도 몇 일정도 이 TDD라는 녀석에 대해서 검색도 해보고, 영상도 보고 나름 이것저것 시행착오를 겪어가며 공부를 하였다.

처음에는 요즘 트렌드라고 하니깐, 그리고 완벽하게는 아니지만, 개발 도중에 발생하는 대다수의 버그를 잡아낼 수도 있다는 이야기를 듣고 무작정 해보려고 테스트 코드 작성법부터 찾아보았다. 하지만 왠지 제대로 작성하고 있는건지 의문이 들었었다.

그래서 그때부터 이론적인 부분부터 실무에서 직접 적용해 본 실무자들이 올린 블로그 글, 유뷰트 관련 영상 등등 이 곳 저 곳에 흩어져 있는 알짜배기 내용들을 읽고 정리하고 연습하기를 반복하였다.

가장 도움이 되었던 블로그 글은 네이버 기술 블로그에 프론트엔드 개발자 분이 올려주신 TDD관련 내용이었다. 그 분의 글을 보면서 실무에서는 어떤 방식으로 테스트 코드를 작성하고 어떤 테스트가 좋은 테스트인지에 대해서도 자세하게 알 수 있었다. 너무 내용이 좋아서 노트 필기를 하며 읽어 보았는데, 나중에 한 번 더 보고 싶을 때 참고할 수 있게 아래에 필기내용을 첨부하였다.

Read more

210308 React 좋은 테스트의 조건과 효과 그리고 테스트 시나리오 작성법


좋은 테스트의 조건과 효과

좋은 테스트란 무엇일까? 무작정 테스트 코드를 작성해보려고 했지만 막상 좋은 테스트란 무엇인지 알지 못했다.

우선 첫 번째, 테스트의 의도가 명확해야 한다. 코드의 가독성은 중요하다. 좋은 코드는 기계가 아닌 사람이 읽기 쉬워야 한다. 누군가 내가 작성한 테스트 코드를 보았을때 한 눈에 어떤 내용을 테스트하고 있는지 파악할 수 있어야 한다. 테스트 코드가 너무 장황해지거나 불필요하게 복잡해진다면 별도의 함수를 만들어 추상화시켜주는 것이 좋다.

두 번째, 좋은 테스트란 빠른 피드백을 받을 수 있으며, 개발 속도를 빠르게 할 수 있도록 해야 한다. 테스트 결과를 보기 위해 오랫동안 기다려야 하는 테스트는 개발 과정에서 좋지 않다.

Read more

210306 React TDD Practice Mini Project


TDD방식으로 React 개발하기 위한 연습 프로젝트

test의 필요성

  1. documentation (문서화 작업)
    테스트 코드는 코드가 어떻게 동작을 해야 되는지에 대한 정의를 하고 있다.

  2. consistency (지속성)
    Software developer들이 팀을 위한 최선의 practices와 conventions을 따를 수 있게 도와준다.

  3. Confidence (자신감)
    warm blanket 코드를 작성할때 좀 더 자신감 있게 코드를 작성할 수 있도록 도와준다.

  4. Productivity (생산성)
    테스트는 높은 품질의 코드를 빠르게 작성할 수 있도록 도와준다

Read more

210217 Jest의 test, it, describe


이번 포스팅에서는 Jest에서 테스트 코드를 작성할때 사용하는 test와 it 키워드의 사용과 여러 개의 테스트 케이스를 묶을때 사용하는 describe 키워드에 대해서 정리를 해보겠다.

test와 it 키워드의 사용

이전 포스팅에서 test라는 키워드를 사용해서 테스트 케이스를 작성해보았다. 이 키워드를 대체해서 it이라는 키워드도 사용될 수 있는데 작동 방식은 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// test keyword를 사용한 테스트 코드 작성
const { test, expect } = require('@jest/globals');
const sum = require('../sum');

// 작성한 테스트코드가 무엇을 하는지에 대해서 첫번째 parameter로 작성해준다.
test('properly adds two numbers', () => {
// expected result
expect(sum(1, 2)).toBe(3);
});

// it keyword를 사용한 테스트 코드 작성
it('properly adds two numbers', () => {
expect(sum(1, 2)).toBe(3);
});
Read more

210208 Jest의 다양한 matcher


Jest Matcher

이전에 사용했던 toBe() matcher는 숫자나 문자와 같은 기본 타입(Primitive Type)의 데이터를 비교할때 사용했다. 그럼 그 외에 다른 matcher에는 어떤 것들이 있는지 알아보고 실습을 해보도록 하겠다.

Jest의 다양한 matcher

  • toEqual() : primitive type의 변수나 객체를 비교할때 사용된다.
    객체는 참조변수이기 때문에 값은 같더라도 참조하는 주소가 다르다.

  • toStrictEqual() : 객체를 좀 더 엄격하게 검사할때 사용된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // makeUser()를 toEqual()로 검사를 하게 되면 passed
    // toStrictEqual()를 toEqual()로 검사를 하게 되면 failed
    const fn = {
    add: (a, b) => a + b,
    makeUser: (name, age) => ({ name, age, gender: undefined }),
    throwErr: () => {
    throw new Error('xx');
    }
    };
Read more

210208 Jest의 개념과 기본사용


Jest

Jest는 Facebook에 의해서 개발된 JavaScript 테스트 프레임워크이며, 대규모 Web application의 테스트를 좀 더 심플하게 할 수 있도록 도와준다.

Jest framework의 사용

간단한 JavaScript 코드를 Jest framework를 사용해서 테스트 해보도록 하자.

실습 내용

실습 Repository : https://github.com/LeeHyungi0622/javascript-jest-test-practice-repo

  1. 프로젝트의 branch 기본 구성은 master branch로 구성한다.

  2. README.md 파일의 documentation작업을 제외한 모든 작업은 별도의 branch를 새로 끊어서 작업을 시작한다.


Read more