Spring

[Spring] JUnit5 테스트 코드 작성

테런 2023. 10. 6. 14:36
  • 테스트 코드를 작성해야 하는 이유
코드 테스트는 소프트웨어 개발 과정에서 매우 중요한 부분입니다. 아래는 코드 테스트를 실시해야하는 이유 몇 가지입니다.

1. 버그 발견: 코드 테스트를 통해 프로그램 내의 버그와 오류를 식별할 수 있습니다. 이렇게 발견된 버그를 수정하면 소프트웨어의 안정성과 신뢰성을 높일 수 있습니다.

2. 기능 검증: 코드 테스트는 소프트웨어의 기능을 확인하는 데 사용됩니다. 시스템이 기대대로 작동하는지 확인하고, 모든 기능이 올바르게 구현되었는지 확인할 수 있습니다.

3. 코드 변경 관리: 코드를 수정하거나 업데이트할 때, 테스트를 통해 변경된 코드가 이전 버전과 호환되는지 확인할 수 있습니다. 이를 통해 새로운 기능 추가나 버그 수정을 안정적으로 수행할 수 있습니다.

4. 코드 문서화: 테스트 코드는 소프트웨어의 동작을 설명하고 문서화하는 데 도움이 됩니다. 다른 개발자나 팀원들이 코드를 이해하고 유지보수하기 쉽게 만들어줍니다.

5. 성능 평가: 코드 테스트를 통해 소프트웨어의 성능을 측정하고 병목 현상을 찾을 수 있습니다. 이를 통해 최적화나 개선 작업을 수행할 수 있습니다.

6. 보안 강화: 코드 테스트를 통해 보안 취약점을 찾아내고 이를 수정하여 시스템을 보다 안전하게 만들 수 있습니다.

7. 회귀 테스트: 코드 변경 후에 이전에 작동하던 기능이 여전히 정상적으로 작동하는지 확인하기 위해 회귀 테스트를 수행할 수 있습니다.

코드 테스트는 소프트웨어 개발 생명 주기의 중요한 부분이며, 소프트웨어의 품질을 향상시키고 개발 및 유지보수 비용을 절감하는 데 도움을 줍니다. 그러므로 코드를 신중하게 테스트하고 테스트 스위트를 작성하는 것은 개발 프로세스에서 필수적입니다.

 

 

  • Layered Architecture에서 테스트 Java 코드 작성 예시
Layered Architecture에서는 각 Layer 별로 테스트를 작성하여 소프트웨어의 각 부분을 독립적으로 테스트합니다. 아래에는 Java를 사용한 Layer 별 테스트 코드의 예시를 제공합니다.

1. Presentation Layer 테스트: Presentation Layer는 사용자 인터페이스와 상호작용합니다.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testUserCreation() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.post("/user")
                .param("username", "testuser")
                .param("password", "testpassword"))
                .andExpect(status().isOk());
    }

    @Test
    public void testUserLogin() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.post("/login")
                .param("username", "testuser")
                .param("password", "testpassword"))
                .andExpect(status().isOk());
    }
}​


2. Business Logic Layer 테스트: Business Logic Layer는 애플리케이션의 핵심 로직을 처리합니다.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class UserServiceTest {

    @Test
    public void testCreateUser() {
        UserService userService = new UserService();
        String result = userService.createUser("testuser", "testpassword");
        assertEquals("User created successfully", result);
    }

    @Test
    public void testLoginUser() {
        UserService userService = new UserService();
        String result = userService.loginUser("testuser", "testpassword");
        assertEquals("Login successful", result);
    }
}


3. Data Access Layer 테스트: Data Access Layer는 데이터베이스와 상호작용합니다.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class UserRepositoryTest {

    @Test
    public void testCreateUser() {
        UserRepository userRepository = new UserRepository();
        boolean result = userRepository.createUser("testuser", "testpassword");
        assertTrue(result);
    }

    @Test
    public void testGetUserByUsername() {
        UserRepository userRepository = new UserRepository();
        User user = userRepository.getUserByUsername("testuser");
        assertNotNull(user);
    }
}


이러한 테스트 코드를 작성하면 각 계층의 기능을 분리하여 테스트할 수 있으며, 계층 간의 의존성을 최소화하고 문제를 식별하여 수정하기가 쉬워집니다.

 

 

  • BDD (Behavior-Driven Development) 개념
BDD (Behavior-Driven Development)는 소프트웨어 개발 방법론 중 하나로, 소프트웨어의 행동과 기능을 중심으로 개발하고 테스트하는 접근 방식입니다. BDD는 소프트웨어의 기능과 동작에 대한 명확하고 이해하기 쉬운 설명을 제공하며, 개발자, 품질 보증(QA) 팀, 비즈니스 이해 관계자와의 커뮤니케이션을 개선하기 위해 사용됩니다.

BDD의 주요 특징과 원칙은 다음과 같습니다.

1. 행동 중심: BDD는 소프트웨어의 기능과 동작에 중점을 둡니다. 소프트웨어가 어떻게 행동해야 하는지를 명시적으로 정의하고 이를 기반으로 개발 및 테스트를 수행합니다.

2. 이해 관계자와의 협력: BDD는 비즈니스 이해 관계자와 개발자, 품질 보증(QA) 팀 간의 협력을 강조합니다. 비즈니스 이해 관계자와 함께 요구사항과 기능을 명세화하고 공유함으로써 소프트웨어 개발의 정확성과 일치성을 확보합니다.

3. 자연어 사용: BDD에서는 자연어와 유사한 형식을 사용하여 기능과 시나리오를 작성합니다. 이는 모든 이해 관계자가 이해하기 쉽고, 소프트웨어의 동작을 설명하기에 유용합니다.

4. 시나리오 기반 테스트: BDD에서는 시나리오를 작성하고 이를 테스트 케이스로 사용합니다. 시나리오는 소프트웨어가 특정 상황에서 어떻게 동작해야 하는지를 나타냅니다.

5. 도구 지원: BDD를 구현하는 데 도움이 되는 다양한 도구가 있습니다. 예를 들어, Cucumber, SpecFlow, Behave 등의 도구는 BDD 시나리오를 작성하고 실행하는 데 사용됩니다.

BDD는 소프트웨어의 기능을 명확하게 정의하고 개발 및 테스트를 효율적으로 수행할 수 있도록 도와주며, 비즈니스 요구사항을 소프트웨어로 옮기는 데 도움을 줍니다. 이는 소프트웨어의 품질을 향상시키고 개발 과정에서의 협력과 의사소통을 강화하는 데 도움이 됩니다.

아래는 예시입니다.

* Given / When / Then
- Given: 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)
- When: 시나리오 행동 진행
- Then: 시나리오 진행에 대한 결과 명시, 검증 -> 어떤 환경에서, 어떤 행동을 진행했을 때, 어떤 상태 변화가 일어난다.
@DisplayName("")
@Test
void TestCode() {
    // given

    // when

    // then
}​

 

 

  • 통합 테스트와 유닛 테스트의 개념
통합 테스트(Integration Testing)와 유닛 테스트(Unit Testing)는 소프트웨어 테스트의 두 가지 주요 유형입니다. 이 두 유형의 테스트는 서로 다른 범위와 목적을 가지며, 소프트웨어 품질을 보장하고 개발 프로세스를 지원합니다.

1. 유닛 테스트(Unit Testing)
- 유닛 테스트는 소프트웨어의 가장 작은 단위인 "유닛"을 개별적으로 테스트하는 것을 의미합니다. 이 유닛은 일반적으로 함수, 메서드, 클래스 또는 모듈과 같은 작은 코드 조각을 나타냅니다.

- 유닛 테스트는 소프트웨어의 각 구성 요소가 올바르게 작동하는지 확인하는 데 중점을 둡니다. 함수 또는 메서드가 예상대로 입력을 받고 올바른 출력을 생성하는지를 테스트합니다.

- 유닛 테스트는 개발 초기 단계에서 빠르게 피드백을 제공하며, 코드 리팩터링과 버그 수정에 도움이 됩니다.
- 주로 자동화되며, 테스트 프레임워크(예: JUnit, NUnit, pytest 등)를 사용하여 작성됩니다.

2. 통합 테스트(Integration Testing)
- 통합 테스트는 여러 유닛이 함께 작동하여 시스템의 다양한 부분이 상호작용하는 방식을 검증하는 것을 목표로 합니다. 즉, 다른 유닛들 간의 통합을 테스트합니다.

- 통합 테스트는 유닛 테스트를 통과한 개별 유닛을 결합하여 시스템 수준의 기능과 동작을 테스트합니다. 이로써 다른 컴포넌트와의 상호 작용, 데이터 흐름, 서비스 호출 등을 확인할 수 있습니다.

- 시스템의 전반적인 품질과 성능을 테스트하기 위해 사용됩니다. 예를 들어, 웹 애플리케이션의 통합 테스트에서는 사용자 인터페이스, 백엔드 서비스, 데이터베이스 등이 모두 통합되어 동작하는지를 확인합니다.

- 자동화되며, 여러 통합 테스트 케이스가 시스템의 통합 환경에서 실행됩니다.

요약하면, 유닛 테스트는 소프트웨어의 작은 구성 요소를 개별적으로 테스트하고, 통합 테스트는 이러한 유닛들을 결합하여 시스템 전체의 동작을 확인하는 역할을 합니다. 두 유형의 테스트 모두 소프트웨어 개발 과정에서 중요하며, 품질 보증 및 버그 식별에 큰 도움을 줍니다.