[Node] 테스팅 일대기

김시원·2023년 5월 11일
0

Node

목록 보기
4/5
post-thumbnail
post-custom-banner


계속 업데이트 예정 😎

📌 jest Unit Test

단위 테스트란

동작/기능을 단위로 하여 검증하고, 빠르게 수행하고, 격리된 방식으로 처리하는 테스트

  • 기본적인 비지니스 로직과 예외 사항들
  • 인프라 구성 요소 대신 가짜 또는 모의 개체로 알려져 있는 제작된 구성 요소를 사용

단위 테스트의 목표

  • 테스트에 드는 노력은 최소, 그에 따른 이득은 최대화
  • 코드는 점점 나빠지는 경향이 있다. 변경이 생길 때마다 무질서도가 높아진다. 따라서, 지속적인 관리를 위해 테스트 코드는 필수적이다.
  • 코드 변경시 테스트를 수행하고, 제품 코드를 리팩토링할 때 테스트도 리팩토링한다.

성공적인 unit test suite

  • 테스트는 자동으로 확인할 수 없다! 따라서, 개발 주기에 통합되어 있어야한다.
  • 가장 중요한 부분 (비지니스 로직, 도메인 모델)을 대상으로 해야한다.

jest 사용기

  • 각 메서드 안에서 사용하는 함수를 재정의해주는 것이 핵심! Mocking이라고 한다. Model, function 모두 원래 함수의 동작을 모방하되 테스트용으로 return value를 지정해주면 된다.
    jest.fn(() => returnValue)

📌 supertest Integration Test

통합 테스트란

동작/기능을 단위로 하여 검증하고, 빠르게 수행하고, 격리된 방식으로 처리하는 테스트

  • 단위 테스트는 하나의 메서드가 잘 동작한다는 것은 보장할 수 있지만, 그들이 결합되었을 때도 잘 작동한다는 보장을 할 수 없기 때문에, 통합 테스트를 해야한다.
  • 주요 흐름과 단위 테스트가 다루지 못하는 edge case
  • 앱이 프로덕션 환경에서 사용하는 실제 구성 요소를 사용
    더 많은 코드와 데이터 처리가 필요
  • 테스트용 데이터베이스를 만들어준다.

통합 테스트의 목표

  • 모듈들의 상호 작용 확인

jest supertest 사용기

1) 로그인 상태를 유지해야한다. 즉, 토큰을 담은 cookie들을 계속해서 지니고 있어야한다.

  • 이를 위해, accessToken과 refreshToken을 login API에서 발급하면 이를 다른 객체에 저장해주었다.
  • 이를 auth-middleware를 통과하는 API들에 대해 header에 cookie를 직접 넣어주었다.
const response = await supertest(app)
      .post(`/api/worldcup`) // API의 HTTP Method & URL
      .set("Authorization", `Bearer ${userData.accessToken}`) // 헤더에 Access Token 세팅
      .set("refreshtoken", `${userData.refreshToken}`) // 헤더에 Refresh Token 세팅
      .send(createWorldcupRequestBodyParams); // Request Body

이 방식을 사용하면 매번 test를 진행할때마다 요청이 새롭게 생성된다.
2) agent()를 사용하여 요청을 지속시킬 수 있다.

  • agent는 브라우저가 쿠키를 기본으로 보내는 것처럼 비슷한 행동을 할 수 있는 메서드이다.
describe('POST /api/auth/login', () => {
	const agent = request.agent(app);
	beforeEach((done) => {
		agent.post('/api/auth/login')
			 .send({
				 nickname: userData.nickname,
			      password: userData.password,
			      email: userData.email,
			 })
			 .end(done);
	});

	test("POST /api/worldcup", async () => {
	    const createWorldcupRequestBodyParams = {
	      title: worldcupData2.title,
	      content: worldcupData2.content,
	      choices: worldcupData2.choices,
	    };
	    const response = await agent
	      .post(`/api/worldcup`)
	      .send(createWorldcupRequestBodyParams);
		
		expect(response.status).toEqual(201)
		expect(response.body).toMatchObject({
		      newWorldcup: {
		        worldcup_id: worldcupData2.worldcup_id,
		        user_id: userData.user_id,
		        title: createWorldcupRequestBodyParams.title,
		        content: createWorldcupRequestBodyParams.content,
		        choices: createWorldcupRequestBodyParams.choices,
		      },
		    });
	  });
});

📌 Artillery Load Test

부하 테스트란

임계치의 한계에 도달할 때까지 부하를 꾸준히 증가시키며 진행하는 테스트. 즉, 서버가 얼마만큼의 요청을 견딜 수 있는지 테스트하는 것이다.

  • 내 코드가 실제로 배포되었을 때, 어떤 문법적, 논리적 문제가 있을지는 유닛 테스트와 통합 테스트를 통해 어느 정도 확인할 수 있지만, 내 서버가 몇 명의 동시 접속자나 일일 사용자를 수용할 수 있는지 예측하는 것은 매우 어렵다.
  • 코드에 문법적, 논리적 문제가 없더라도 서버의 하드웨어 제약으로 인해 서비스가 중단될 수 있다.
  • 대표적인 것이 OOM(out of memory) 문제인데, 이는 서버가 접속자들의 정보 저장을 위해 각 사용자마다 일정한 메모리를 할당할 때, 메모리의 양이 계속 증가하다가 결국 서버의 메모리 용량을 넘어서게 되면 발생하는 문제이다.
  • 이런 것들을 부하 테스트를 통해 어느 정도 예측할 수 있다.

Artillery 사용기

사용 방법 포스팅

📌 TDD: Test-Driven Development

TDD와 기존 프로세스의 차이

TDD란

  • 애자일 방법론 중 하나인 eXtream Programming (XP)의 'Test-First' 개념에 기반을 둔, 테스트 주도 개발이다.
    - XP: 미래에 대한 예측을 최대한 하지 않고, 지속적으로 프로토타입을 완성하는 애자일 방법론 중 하나이다. 이 방법론은 추가 요구사항이 생기더라도, 실시간으로 반영할 수 있다.

    Red: 실패하는 테스트 코드 작성
    Green: 테스트 코드를 성공시키기 위한 실제 코드 작성
    Refactor: 중복 코드 제거, 일반화 등의 리팩토링

  • 핵심
    1) 실패하는 테스트 코드를 작성할 때까지 실제 코드를 작성하지 않는 것
    2) 실패하는 테스트를 통과할 정도의 최소 실제 코드를 작성하는 것

TDD로 개발해야 하는 케이스 = 불확실성이 높을 때

  • 처음 해보는 프로젝트 수행시 (내부적인 불확실성)
  • 고객의 요구조건이 바뀔 수 있는 프로젝트 수행시 (외부적인 불확실성)
  • 개발하는 중에 코드를 많이 바꿔야한다고 생각되는 경우
  • 내가 개발하고 나서, 누가 유지보수를 할 지 모르는 경우 (외부적인 불확실성)

TDD의 장점

  • 튼튼한 객체 지향적인 코드 생산 - TDD는 코드의 재사용을 보장하여 기능별 철저한 모듈화가 이루어진다.
  • 재설계 시간의 단축 - 개발자가 무슨 코드/로직을 짜야하는지 분명히 정의하고 개발을 시작할 수 있다.
  • 디버깅 시간의 단축 - 유닛 테스트의 이점, 어떤 레이어에서 문제가 발생하는지 파악하기 용이하다.
  • 추가 구현의 용이함 - 추가 기능 구현시 기존 코드에 영향을 미치는 것에 조심해야 하는데, TDD는 자동화된 유닛 테스팅을 전제하므로 테스트 기간을 단축할 수 있다.

TDD의 단점

  • 생산성 저하: 개발 속도가 느려질 수 있다. 실제, 일반적인 개발 방식보다 10~30%정도 시간이 늘어난다. 따라서, SI 프로젝트의 경우 TDD를 잘 채택하지 않는다.
post-custom-banner

0개의 댓글