[Spring] JUnit과 AssertJ로 테스트 코드 작성하기

Spring에서 주로 사용하는 JUnit과 AssertJ를 왜, 어떻게 사용하는 지 예시 코드를 통해 살펴보자.
Hi's avatar
Apr 20, 2024
[Spring] JUnit과 AssertJ로 테스트 코드 작성하기
 

✅ 들어가기 전에

테스트 코드를 작성하는 이유가 무엇일까?
개발 단계에서 테스트 코드를 작성하는 이유는 정말 다양할 것이다. 그 중에서도 가장 손꼽히는 이유는:
  • 개발 과정에서 문제를 미리 예측 및 발견할 수 있다.
  • 애플리케이션을 직접 가동해서 테스트하는 것보다 테스트를 빠르게 진행할 수 있다.
  • 단위 테스트를 통해 각각의 기능 별 테스트가 가능하다.
  • 코드가 작성된 목적을 명확하게 표현할 수 있으며, 불필요한 내용이 추가되는 것을 방지한다.
  • 버그를 미리 발견하여 리팩토링의 리스크가 줄어든다.
 
📋
스프링 부트는 애플리케이션을 테스트하기 위한 도구와 어노테이션을 제공한다. 아래와 같은 여러 테스트 도구가 spring-boot-starter-test에 들어있다.
 
  • JUnit
    • 자바 프로그래밍 언어용 단위 테스트 프레임워크
  • Spring Test & Spring Boot Test
    • 스프링 부트 애플리케이션을 위한 통합 테스트 지원
  • AssertJ
    • 검증문인 어설션을 작성하는 데 사용
  • Hamcrest
    • 표현식을 보다 이해하기 쉽게 만드는 데 사용되는 Matcher 라이브러리
  • Mockito
    • 테스트에 사용할 가짜 객체인 mock 객체를 쉽게 만들고, 관리하고, 검증할 수 있게 지원하는 테스트 프레임워크
  • JSONassert
    • JSON 용 어설션 라이브러리
  • JsonPath
    • JSON 데이터에서 특정 데이터를 선택하고 검색하기 위한 라이브러리
 
→ 이 중에서 JUnit과 AssertJ를 가장 많이 사용한다!
 

✅ JUnit이란?

📋
JUnit은 자바 언어를 위한 단위 테스트 프레임워크이다. 단위 테스트란, 작성한 코드가 나의 의도에 맞게 동작하는 지 작은 단위로 검증하는 것을 말한다(이때 보통 단위는 하나의 메소드를 의미한다).
 

JUnit의 특징

  • @Test 어노테이션으로 메소드를 호출할 때마다 새로운 인스턴스를 생성한다.
  • 예상 결과를 검증하는 Assertion 메소드를 제공한다.
  • 사용법이 단순하다.
  • 자동으로 실행하고, 자체적으로 결과를 확인해 피드백을 제공한다.
 

코드 예시

@Test @DisplayName("상품 1개 등록하기 - TestRestTemplate 기반") void createProduct() { // given Long adminId = 1L; String name = "보조배터리"; Long price = 10000L; String category = "전자기기"; String thumbnailUrl = "http://abc.com"; ProductRequestMvc productRequestMvc = ProductRequestMvc.builder() .adminId(adminId) .name(name) .price(price) .category(category) .thumbnailUrl(thumbnailUrl) .build(); String url = "http://localhost:" + port + "/mvc/product/create"; // API url 주소 // when ResponseEntity<ProductResponseMvc> responseEntity = testRestTemplate.postForEntity(url, productRequestMvc, ProductResponseMvc.class); // then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); ProductEntityMvc savedProduct = productServiceMvc.findById(responseEntity.getBody().getId()); Assertions.assertEquals(savedProduct.getAdminId(), adminId); Assertions.assertEquals(savedProduct.getName(), name); Assertions.assertEquals(savedProduct.getPrice(), price); Assertions.assertEquals(savedProduct.getCategory(), category); Assertions.assertEquals(savedProduct.getThumbnailUrl(), thumbnailUrl); }
 

Given-When-Then Pattern

코드를 자세히 살펴보았다면, given, when, then이라 주석처리 되어 있는 부분을 발견했을 것이다. given, when, then이 무엇일까? 이것은 테스트 코드를 작성할 때 흔히 사용하는 패턴이다. 테스트 진행 프로세스를 3가지로 나누어 각각에 맞는 작업을 수행하는 것이다.
  • given: 테스트 하기 위해 기본적으로 세팅하는 절차이다.
  • when: 테스트를 하기 위한 조건을 지정한다.
  • then: 테스트 하기 위한 행위와 결과값이 우리가 예상하는대로 잘 수행되는지 검증한다.
 
이렇게 3가지 부분으로 나누어 테스트를 하기 위한 목적이 무엇인지 명확히 할 수 있다. 위 예시 코드에서 각각 수행하는 역할은 아래와 같다.
 
  • given
    • 상품 객체를 하나 생성한다.
  • when
    • testRestTemplate을 통해 상품 등록 API를 실행한다.
  • then
    • 상품이 잘 저장되었는지 서비스를 통해 가져와서 속성을 비교하며 확인한다.
    • Assertions.assertEquals(savedProduct.getAdminId(), adminId);에서 savedProduct.getAdminId()는 검증하고 싶은 값을 의미하고, adminId는 실제 비교할 값을 의미한다.
 
위와 같은 상품을 등록하는 간단한 코드를 JUnit을 통해 작성할 수 있다.
 

✅ AssertJ로 검증문 수정하기

AssertJ는 JUnit과 함께 사용하여 검증문의 가독성을 높여주는 라이브러리이다. 위 테스트 코드의 Assertions를 통한 검증문은 기댓값과 실제 비교값을 명시하지 않으므로 비교 대상이 헷갈릴 수 있다.
이를 해결하기 위해 AssertJ를 사용하여 코드를 아래와 같이 수정할 수 있다.
 
Assertions.assertEquals(savedProduct.getAdminId(), adminId);
Assertions 사용 코드
 
assertThat(savedProduct.getAdminId()).isEqualTo(adminId);
AssertJ 사용 코드
 
위처럼 assertThat()을 사용하면, 검증할 값과 실제 비교 대상을 명확하게 표현할 수 있다. 따라서, 수정한 최종 코드는 아래와 같다.
 
@Test @DisplayName("상품 1개 등록 - TestRestTemplate 기반") void createProduct() { // given Long adminId = 1L; String name = "보조배터리"; Long price = 10000L; String category = "전자기기"; String thumbnailUrl = "http://abc.com"; ProductRequestMvc productRequestMvc = ProductRequestMvc.builder() .adminId(adminId) .name(name) .price(price) .category(category) .thumbnailUrl(thumbnailUrl) .build(); String url = "http://localhost:" + port + "/mvc/product/create"; // when ResponseEntity<ProductResponseMvc> responseEntity = testRestTemplate.postForEntity(url, productRequestMvc, ProductResponseMvc.class); // then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); ProductEntityMvc savedProduct = productServiceMvc.findById(responseEntity.getBody().getId()); assertThat(savedProduct.getAdminId()).isEqualTo(adminId); assertThat(savedProduct.getName()).isEqualTo(name); assertThat(savedProduct.getPrice()).isEqualTo(price); assertThat(savedProduct.getCategory()).isEqualTo(category); assertThat(savedProduct.getThumbnailUrl()).isEqualTo(thumbnailUrl); }
 
위에서 사용한 isEqualTo()는 값이 같은지 검증하는 코드이다. 이 외에도 아래와 같이 여러가지 다양한 검증 메소드가 존재한다.
 
메소드
설명
isEqualTo(X)
X 값과 같은지 검증
isNotEqualTo(X)
X 값과 다른지 검증
contains(X)
X 값을 포함하는지 검증
doesNotContain(X)
X 값을 포함하지 않는지 검증
startsWith(X)
접두사가 X인지 검증
endsWith(X)
접미사가 X인지 검증
isEmpty(X)
비어있는 값인지 검증
isNotEmpty()
비어있지 않은 값인지 검증
isPositive()
양수인지 검증
isNegative()
음수인지 검증
isGreaterThan(N)
N보다 큰 값인지 검증
isLessThan(N)
N보다 작은 값인지 검증
 
추후에 Mock, TestRestTemplate 등에 대해서도 알아보자!
 
Share article

soultree