2 minute read

Test

단위 테스트

  • 테스트 가능한 가장 작은 소프트웨어를 실행하여 예상대로 동작하는지 확인하는 테스트
  • 개발자 관점
  • 일반적으로 클래스 또는 메소드 수준으로 정해짐
  • 되도록 단위의 크기를 작게 설정해, 간단하고 디버깅하기 쉽게 작성해야 한다.

Java Spring에서는 JUnit을 통해 단위 테스트를 수행할 수 있다.

  • @DataJpaTest, @ExtendWith(MockitoExtension.class), @WebMvcTest 등의 어노테이션을 활용해 수행할 수 있다.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@SpringJUnitConfig
@SpringBootTest
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @MockBean
    private UserRepository userRepository;

    @Test
    public void testGetUserById() {
        // 가짜 데이터 생성
        User mockUser = new User();
        mockUser.setId(1L);
        mockUser.setName("John Doe");

        // UserRepository의 findById 메서드가 호출될 때 가짜 데이터 반환하도록 설정
        when(userRepository.findById(1L)).thenReturn(mockUser);

        // UserService의 getUserById 메서드 호출
        User user = userService.getUserById(1L);

        // 결과 확인
        assertEquals("John Doe", user.getName());
    }
}

통합 테스트

  • 단위 기능 간의 의존성을 포함하여 테스트
  • 개발자 관점
  • 단위 테스트에서 가짜 객체로 배제하였던 부분을 함께 테스트
  •  클래스 상단에 @SpringBootTest 어노테이션을 붙여 통합 테스트를 수행할 수 있다.

인수 테스트

  • 사용자 관점
  • 소프트웨어를 인수하기 전에 명세대로 작동하는지 검증하는 테스트
  • 시나리오 베이스 테스트
  • 도구
    • MockMVC : 모킹한 Spring MVC 환경을 구현해 테스트
    • RestAssured : 실제 서버를 구동해 실제 환경에서 테스트
    • WebTestClient

stub, mock

stub 

  • 더미 객체를 생성하고 실제로 동작하는것처럼 보이게 만든 가짜 객체
  • 요청에 대한 응답값을 미리 만들어 전달한다. 
  • 최소한의 기능만을 구현한다. 

mock

  • 특정 동작을 수행하는지(= 메소드를 제대로 콜 하는지)에 대한 검증을 한다.
  • 행위검증을 추구한다는 점에서 다른 테스트 더블들과 구분된다.

SpringBoot 계층별 테스트 방법

Controller

  • Spring MVC의 요청-응답 흐름을 테스트
  • 주로 HTTP 요청과 관련된 동작을 테스트하며, 컨트롤러의 메소드를 직접 호출하여 응답을 검증한다.
  • 일반적으로 MockMvc를 사용하여 컨트롤러 테스트를 수행한다.
@RunWith(SpringRunner.class)
@WebMvcTest(YourController.class)
public class YourControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testYourControllerMethod() throws Exception {
        mockMvc.perform(get("/your-url"))
                .andExpect(status().isOk())
                .andExpect(content().string("Expected Response"));
    }
}

Repository

  • 데이터베이스와의 상호 작용을 테스트
  • 데이터베이스에 대한 CRUD(Create, Read, Update, Delete) 작업을 검증
  • 내장된 H2 데이터베이스 또는 외부 데이터베이스를 사용할 수 있다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class YourRepositoryTest {

    @Autowired
    private YourRepository yourRepository;

    @Test
    public void testYourRepositoryMethod() {
        // Your test logic using the repository
        // Example:
        YourEntity entity = new YourEntity();
        entity.setName("Test");
        YourEntity savedEntity = yourRepository.save(entity);

        Optional<YourEntity> foundEntity = yourRepository.findById(savedEntity.getId());
        assertTrue(foundEntity.isPresent());
        assertEquals("Test", foundEntity.get().getName());
    }
}

Service

  • 비즈니스 로직을 테스트
  • 비스 메소드의 동작과 로직을 검증
  • Repository를 Mock으로 대체하여 테스트를 수행
@RunWith(MockitoJUnitRunner.class)
public class YourServiceTest {

    @InjectMocks
    private YourService yourService;

    @Mock
    private YourRepository yourRepository;

    @Test
    public void testYourServiceMethod() {
        // Define mock behavior
        YourEntity entity = new YourEntity();
        entity.setName("Test");
        Mockito.when(yourRepository.findById(1L)).thenReturn(Optional.of(entity));

        // Your test logic using the service
        // Example:
        YourEntity foundEntity = yourService.getEntityById(1L);
        assertNotNull(foundEntity);
        assertEquals("Test", foundEntity.getName());
    }
}

Domain

  • Domain 로직은 JUnit 나 AssertJ 등 테스트 편의 도구 외 다른 프레임워크의 도움이 필요하지 않다.
  • 비즈니스 도메인 객체의 동작 테스트
  • 도메인 객체의 메소드와 로직 검증
public class YourDomainTest {

    @Test
    public void testYourDomainMethod() {
        // Your test logic using the domain object
        // Example:
        YourDomainObject domainObject = new YourDomainObject();
        domainObject.setValue("Test");

        assertEquals("Test", domainObject.getValue());
    }
}

테스트 커버리지(JACOCO)

  • Jacoco 툴을 통해 테스트 커버리지를 체크할 수 있다.
    • 테스트 코드가 현재 프로덕션코드의 얼마만큼 작성되었는지 퍼센테이지로 확인하도록 해주는 라이브러리
    • 커버리지가 사용자가 설정한 퍼센테이지에 미치지 못하면 build자체가 되지않게 설정됨
    • 의존성을 추가하여 사용할 수 있다.

테스트 레벨

  • 단위 테스트 (Unit Test)
    • 테스트 가능한 가장 작은 소프트웨어가 예상대로 동작하는지 확인 (Java는 주로 Junit사용)
  • 통합 테스트 (Integration Test)
    • 내부 모듈의 연동과 외부 모듈의 연동을 테스트함 (springboot의 경우 @SpringBootTest)
  • 인수 테스트 (Acceptance Test)
    • 사용자 시나리오에 맞춰 수행하는 테스트
    • end to end (Java에서는 RestAssured, MockMVC 사용)

Leave a comment