테스트 코드와 TDD

EunBeen Noh·2024년 4월 2일
0

SpringAdvanced

목록 보기
1/6
post-thumbnail

테스트의 종류

  • 단위 테스트(Unit Test)

    테스트 가능한 가장 작은 소프트웨어를 실행하여 예상대로 동작하는지 확인하는 테스트
    • 단위는 엄격하게 정해져 있지 않지만, 일반적으로 클래스 또는 메소드 수준의 단위
    • 개발자 관점에서의 테스트
    • Java는 주로 JUnit으로 테스트
  • 통합 테스트(Integration Test)

    단위 테스트보다 더 큰 동작을 달성하기 위해 여러 모듈들을 모아 이들이 의도대로 협력하는지 확인하는 테스트
  • 인수 테스트(Acceptance Test)

    사용자 스토리(시나리오)에 맞춰 수행하는 테스트

단위 테스트의 중요성

  • 코드 수정 및 기능 추가 시 수시로 빠르게 검증 가능
    • 통합 테스트를 위해서는 캐시, 데이터베이스 등 외부 컴포넌트들과 연결 등 부가적인 시간이 필요하기 때문
  • 코드 리팩토링 시 안정성 확보 가능
  • 개발/테스팅 시간과 비용 절감

단위 테스트 코드 패턴

주로 한개의 단위를 3가지로 나눠서 처리하는 given-when-then 패턴을 사용

  • given(준비): 어떠한 데이터가 준비되었을 때,
  • when(실행): 어떠한 함수를 실행하면, (조건을 지정)
  • then(검증): 어떠한 결과가 나와야 한다.
  • verify: 메서드가 호출된 횟수, 타임아웃 시간 체크를 검사할 때 사용 (부가적)
	@Test
	public void testFindUserById() {
		// Given
		UserRepository userRepository = Mockito.mock(UserRepository.class);
		UserService userService = new UserService(userRepository);
		Long userId = 1L;
		User user = new User();
		user.setId(userId);
		user.setName("하재훈");
		user.setEmail("haman@example.com");
		Mockito.when(userRepository.findById(userId)).thenReturn(Optional.of(user));

		// When
		User foundUser = userService.findUserById(userId);

		// Then
		Assertions.assertNotNull(foundUser);
		Assertions.assertEquals(userId, foundUser.getId());
		Assertions.assertEquals("하재훈", foundUser.getName());
		Assertions.assertEquals("haman@example.com", foundUser.getEmail());
	}s

좋은 테스트의 특징 (FIRST)

Fast: 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다.
Independent: 각각의 테스트는 독립적이며 서로 의존해서는 안된다.
Repeatable: 어느 환경에서도 반복 가능해야 한다.
Self-Validating: 테스트는 성공 또는 실패로 bool 값으로 결과를 내어 자체적으로 검증되어야 한다.
Timely: 테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.

TDD(Test-Driven Development)란?

  • 테스트 주도 개발로, 테스트 코드를 먼저 작성하는 개발 방법론

TDD의 목적

  • 깔끔한 코드
    • TDD의 리팩토링 단계에서 중복된 코드들이 제거되고, 복잡한 코드들이 정리된다.
  • 개발 비용 절감
  • 프로덕션 코드를 모두 작성한 후, 테스트 코드를 작성하려면 경우의 수가 너무 많아 귀찮아진다.

TDD 방법 및 순서

  1. 실패하는 작은 단위 테스트 작성
  2. 빨리 테스트를 통과하기 위해 프로덕션 코드를 작성한다.
    이를 위해 정답이 아닌 가짜 구현 등을 작성할 수도 있다.
  3. 그 다음의 테스트 코드를 작성한다. 실패 테스트가 없을 경우에만 성공 테스트를 작성한다.
  4. 새로운 테스트를 통과하기 위해 프로덕션 코드를 추가 또는 수정한다.
  5. 1~4단계를 반복하여 실패/성공의 모든 테스트 케이스를 작성한다.
  6. 개발된 코드들에 대해 모든 중복을 제거하며 리팩토링한다.
  • RED(실패하는 코드), GREEN(성공하는 코드), REFACTOR 3단계로 줄여 말하기도 함.

TDD 접근 방법

  • 가짜로 구현하기: 최대한 빨리 테스트를 통과하기 위해 정답이 아닌 가짜 정답을 구현하는 방법
    - 실패하는 테스트를 가장 빠르게 구현하는 방법: 아무 값이나 반환하도록 하는 것
    - 테스트 통과 시, 단계적으로 상수->변수를 사용하도록 변형
  • 삼각측량법: 값이 다른 여러 테스트를 작성하고, 이를 일반화하여 정답을 구현하는 방법
    - 테스트 주도로 추상화된 과정을 일반화하는 과정
    • 삼각 측량 방법은 테스트 예시가 2개 이상일 때에만 추상화를 해야 한다.
  • 명백하게 구현하기: 정답을 바로 구현하는 방법

TDD의 단점

  • 테스트에 대한 많은 경험이 없으면 개발자는 일상 업무의 일부로 일반적으로 테스트를 적용하는 데 어려움을 겪을 수 있다.
  • 기능 개발보다 테스트에 더 많은 시간이 소모되어 개발 기간이 느리다고 생각할 수 있다.

하지만 이런 단점들에 불구하고,
TDD를 사용하면 품질 좋은 코드를 만들 수 있고, 개발과정에서 생길 수 있는 버그들을 사전에 발견할 수 있기 때문에 현업에서 많은 개발자들이 TDD를 사용하고 있다고 한다.

다음 주에는 Junit, Mockito에 대해 더 다뤄볼 예정..

0개의 댓글