Jest를 이용한 TestCode

nGyu·2023년 8월 22일
0

NestJS 햝쨕

목록 보기
2/2
post-thumbnail

NestJS를 하다가 .spec.ts 파일을 보고 이게 무슨 파일인가 구글링을 하다보니, TestCode를 작성하는곳이라고 한다.

하지만, 이 TestCode는 어떻게 작성하는것일까? 그저, 함수 몇개 미리 만들어보고 결과값이 어떻게 나오는지 확인하는것일까?

TestCode ( TC )

우선, TestCode가 무엇인지부터 짚고 넘어가자.

TestCode가 무엇일까?

Unit Test - 기능단위 테스트
Integration Test - 통합 테스트

말 그대로, 기능(동작)단위 테스트를 할 수 있는 코드를 일컷는다.

그런데 왜 이렇게 테스트를 해야하는지는 느낌만 알지 정확히 해야하는지는 잘 알지 못했다.

왜 해야할까?

코드를 조금이라도 작성해본 사람들 아래와 같은 생각을 한번 쯤 해보았으리라 생각한다.

  • 이 값을 받은 메서드(함수)의 리턴값은 어떻게 될까?
  • 코드를 조금 더 깔끔하게 작성할 수 없을까?
  • 이 기능을 따로 함수로 만들면 어떻게 될까?

등등.. 다양한 생각을 했으리라 생각된다. 필자도 그러했다.

그러다가 문득 든 생각이 이 메서드(함수)를 테스트할 수 있으면 좋겠다 라는 생각이다.

그렇다. 테스트코드를 작성하는 이유는 위에 작성한 고민에서 시작된다.

각각의 코드가 서로 너무 의존을 하게 된다면 얼마나 복잡한 프로젝트가 되겠는가? 이를 Unit Test를 진행하며 작성한 코드로 의존성을 낮춰 조금이라도 의존성이 낮은 코드를 만들 수 있으며, 테스트를 진행하며 작성한 코드로 내가 이 코드를 작성하는 의도를 보다 명확히 알게 된다.

마지막으로 가장 좋다고 생각되는 부분인데, 우리는 작업을 하다보면 언젠가 코드의 기능은 그대로 두고 성능 개선이나 구조개선등 리팩토링을 하게 된다. 하지만, 이 리팩토링 과정에서 기존에 잘 작동하던 코드가 갑자기 작동이 안되면 불안하기에.. 이미 통과한 테스트코드로 검증하며 리팩토링을 진행한다면 불안감 보다는 안정감을 느끼며 작업할 수 있게 된다.

그럼 어떻게 하는것인가

필자의 경우 현재 회사에서 NestJS를 하고있고, 이 시리즈 역시 NestJS 이기에 Nest 기준으로 작성을 하지만 다른 언어나 프레임워크에서도 비슷하리라 생각된다.

Jest

JavaScript 진영에서는 TestCode를 작성할 때 Jest를 이용하여 작업을 한다.
정말 다양한 기능들이 존재하고, 쉽고 빠르다. 또, coverage까지 확인할 수 있어 정말 편리한 모듈이다.

파일 구조 및 네이밍

이는 사람마다, 회사마다, 프로젝트마다 다르리라 생각한다. 로직을 담당하는 파일과 같은 폴더에 테스트코드를 작성하는 파일을 만든다던가, test코드를 모아두는 폴더를 따로 만든다던가, 정말 많은 케이스가 있다.

하지만, 필자의 경우 test 폴더에 모아두고 작업을 하는 편이다.

Test코드의 경우 service.spec.ts 와같이 nestJS에서는 [테스트하고자 하는 파일].spec.ts 네이밍을 사용하는것으로 보아 필자도 이대로 사용한다.

Jest

이제야 Jest에 대해서 제대로 알아볼텐데 예제를 통하여 알아보고자 한다.

설치는 → https://jestjs.io/docs/getting-started 이곳에서 보면 편할것이다.

설정

describe(), it()

한 파일에 너무 많은양의 함수와 메서드가 있다면 어떨까? 테스트 결과를 보기에 엄청 힘들것이다. 그래서 describe(), it() 를 이용하여 테스트를 그룹화 할 수 있다.

describe('대그룹1', () => {
	describe('중그룹1', () => {
		it('소그룹1', () => {})
		it('소그룹2', () => {})
		it('소그룹3', () => {})
	})
	describe('중그룹2', () => {
		it('소그룹1', () => {})
		it('소그룹2', () => {})
		it('소그룹3', () => {})
	})
})

beforeEach() , afterEach() / beforeAll(), afterAll()

테스트 마다 설정을 해주어야하는 기본 값들이 있을것이다.

예를들어 const arr = [] 에 3개의 배열을 미리 넣어주는 식의 코드나 DB연결 등 이다. 이런 코드들은 ‘사전세팅’이 필요하기에, before*()을 이용하여 세팅한다.

이제 테스트가 끝나면 정리를 해주는 과정이 필요한데, 이러한 과정을 하기 위해서는 after*()를 이용하여 정리한다.

그런데, before / after 는 같은데 Each와 All이 다르다. 이는 왜 나뉘어져 있을까?

바로, 실행 횟수에따라 다르다.

Each의 경우 각 test 즉, 쉽게 말하면 it()이 호출될 때 마다 계속 동작하는것이다.

All의 경우 각 test 단위가 아닌, 해당 파일의 테스트가 실행될 때 1번만 작동한다.

beforeAll(() => { console.log('이 파일 테스트 시작할 때 한번만 실행')})
beforeEach(() => { console.log('테스트마다 실행')})

afterAll(() => { console.log('이 파일 테스트 종료할 때 한번만 실행')})
afterEach(() => { console.log('테스트마다 종료후 실행')})

/* 아래 테스트들 실행 전 beforeAll 한번 실행 후 동작 */
it('테스트1', () => { 
	/* beforeEach 실행 후 동작 */
	let res = 1 + 1
	/* afterEach 실행 후 종료 */
})

it('테스트2', () => { 
	/* beforeEach 실행 후 동작 */
	let res = 2 + 2
	/* afterEach 실행 후 종료 */
})

it('테스트3', () => { 
	/* beforeEach 실행 후 동작 */
	let res = 3 + 3
	/* afterEach 실행 후 종료 */
})
/* 위 테스트들 종료 전 afterAll 한번 실행 후 종료 */

expect()

expect를 이용해서 검증하고자 하는 값을 검증한다.

it('테스트3', () => { 
	let res = 3 + 3
	expect(res)
})

이 다음부터는 expect()와 함께 사용되는 Matcher를 소개할텐데, 전부 다 소개하는것은 아니고 몇몇가지만 소개하고자 한다.
다양한 Matcher와 예제는 https://jestjs.io/docs/using-matchers 참고를 부탁합니다.
추가로, expect() 와 Mater사이에 not을 붙히면 결과의 not 연산이 된다.

toBe()

단순 값 비교

it('테스트3', () => { 
	let res = 3 + 3
	expect(res).toBe(6) // true
	expect(res).toBe(2) // false
})

toBeDefined()

변수 or 메서드(함수)의 정의 여부 확인

it('테스트3', () => { 
	let res = 3 + 3
	expect(res).toBeDefined() // true
	expect(res1).not.toBeDefined() // true
	expect(res1).toBeDefined() // false
})

toBeTruthy(), toBeFalsy()

true / false 검증

it('테스트3', () => { 
	expect(true).toBeTruthy() // true
	expect(false).toBeTruthy() // false

	expect(false).toBeFalsy() // true
	expect(true).toBeFalsy() // false
})

Reference

https://jestjs.io/

profile
지금보다 내일을, 모레를 준비하자

1개의 댓글

comment-user-thumbnail
2023년 8월 23일

front에서만 jest쓰는 줄 알았더니
같은 js 언어에서는 다 쓰나보네요. 반갑반갑

답글 달기