반응형
소프트웨어 개발에서 테스트 코드는 단순히 오류를 찾는 도구를 넘어, CI/CD(Continuous Integration/Continuous Deployment) 파이프라인과 개발 생산성 향상에 핵심적인 역할을 합니다.
이 글에서는 JPA를 사용한 DB 연결 후 테스트를 작성하는 방법을 단계별로 알아보겠습니다.
1. 🌱 단위 테스트와 통합 테스트의 차이
✅ 단위 테스트(Unit Test)
- 목적: 메서드, 클래스 등 작은 단위의 코드가 올바르게 동작하는지 검증.
- 도구: JUnit, Mockito 등.
- 실행 방식:
@ExtendWith
,@Mock
,@InjectMocks
등을 활용하여 외부 의존성을 모킹(Mock).- 테스트 환경에서 빠르게 검증.
✅ 통합 테스트(Integration Test)
- 목적: 여러 구성 요소(Controller, Service, Repository 등)가 올바르게 협력하는지 검증.
- 도구: Spring Boot Test, H2 Database.
- 실행 방식:
@SpringBootTest
를 활용하여 애플리케이션 컨텍스트를 로드.- 실제 데이터베이스와 연결하거나 테스트용 메모리 데이터베이스 사용.
2. 🌟 준비 사항
2.1 의존성 추가 (Maven 기준)
테스트를 위한 주요 라이브러리를 추가합니다.
의존성을 pom.xml
파일에 추가합니다.
<dependencies>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2 Database (테스트용) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
2.2 테스트 환경 설정 (application.yml
)
테스트 전용 데이터베이스를 설정합니다. 여기서는 H2
를 사용합니다.
application-test.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
3. 🛠 단위 테스트 작성하기
단위 테스트에서는 데이터베이스 대신 Mock을 활용합니다. 예제로 간단한 UserService
의 단위 테스트를 작성해 볼게요.
3.1 User 엔티티 및 리포지토리
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// Getters and Setters
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {}
3.2 UserService
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(String name, String email) {
User user = new User();
user.setName(name);
user.setEmail(email);
return userRepository.save(user);
}
}
3.3 UserService 단위 테스트 작성
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testCreateUser() {
// Given
String name = "John";
String email = "john@example.com";
User user = new User();
user.setName(name);
user.setEmail(email);
when(userRepository.save(any(User.class))).thenReturn(user);
// When
User createdUser = userService.createUser(name, email);
// Then
assertEquals(name, createdUser.getName());
assertEquals(email, createdUser.getEmail());
verify(userRepository, times(1)).save(any(User.class));
}
}
✅ @ExtendWith(MockitoExtension.class)
- 설명:
- JUnit 5(=JUnit Jupiter)와 Mockito를 통합해 사용할 때 필요한 어노테이션입니다.
- Mockito에서 제공하는 Mock 객체를 테스트 클래스에 주입할 수 있도록 설정합니다.
- 사용 시점:
- 단위 테스트에서 Mockito를 사용하여 테스트 대상을 모킹(Mocking)할 때 사용합니다.
✅ @Mock
- 설명:
- Mockito에서 제공하는 어노테이션으로, 가짜 객체(Mock)를 생성합니다.
- 실제 객체 대신 Mock 객체를 사용하여 외부 의존성을 제거하고 코드의 특정 부분만 테스트할 수 있습니다.
- 사용 시점:
- 리포지토리, API 호출 등 실제 객체와 상호작용하지 않고 원하는 동작을 시뮬레이션할 때.
✅ @InjectMocks
- 설명:
- Mockito에서 제공하는 어노테이션으로, 테스트 대상 클래스에 Mock 객체를 주입합니다.
@Mock
으로 생성된 Mock 객체를 테스트 대상 클래스의 생성자나 필드에 자동으로 주입합니다.
- 사용 시점:
- 테스트 대상 클래스에 의존성 주입(DI)이 필요한 경우.
4. 🛠 통합 테스트 작성하기
통합 테스트에서는 실제 데이터베이스와 연결된 환경에서 테스트를 실행합니다.
4.1 통합 테스트 설정
@SpringBootTest
와 @Transactional
어노테이션을 활용해 통합 테스트를 작성합니다.
@SpringBootTest
@Transactional
@ActiveProfiles("test") // test 프로파일 활성화
public class UserIntegrationTest {
@Autowired
private UserRepository userRepository;
@Test
void testSaveAndFindUser() {
// Given
User user = new User();
user.setName("Alice");
user.setEmail("alice@example.com");
// When
userRepository.save(user);
Optional<User> foundUser = userRepository.findById(user.getId());
// Then
assertTrue(foundUser.isPresent());
assertEquals("Alice", foundUser.get().getName());
assertEquals("alice@example.com", foundUser.get().getEmail());
}
}
✅ @SpringBootTest
- 설명:
- Spring Boot 통합 테스트를 실행하기 위한 어노테이션입니다.
- 애플리케이션 전체 컨텍스트를 로드하고 테스트를 수행합니다.
- 사용 시점:
- 여러 Bean 간의 상호작용 및 애플리케이션 전반적인 통합 테스트를 실행할 때.
✅ @Transactional
- 설명:
- 테스트 실행 중 데이터 변경 사항을 롤백하도록 설정합니다.
- 테스트마다 새로운 트랜잭션이 생성되고, 테스트가 끝나면 데이터베이스 상태를 초기화합니다.
- 사용 시점:
- 데이터베이스를 사용하는 통합 테스트에서 DB 상태를 초기화해야 할 때.
✅ @ActiveProfiles
- 설명:
- 특정 Spring Profile을 활성화하도록 설정합니다.
- 이를 통해 테스트 환경, 개발 환경 등 환경별 설정을 분리할 수 있습니다.
- 사용 시점:
application-test.yml
과 같은 테스트 전용 설정 파일을 적용하고 싶을 때.
5. 🎯 정리: 단위 테스트와 통합 테스트의 핵심 비교
특징 | 단위 테스트 | 통합 테스트 |
목적 | 특정 단위의 독립적 검증 | 시스템의 통합된 흐름 검증 |
외부 의존성 | Mock 객체 사용 | 실제 데이터베이스 사용 |
실행 속도 | 빠름 | 상대적으로 느림 |
어노테이션 | @ExtendWith(MockitoExtension.class) |
@SpringBootTest , @Transactional |
단위 테스트는 빠르게 개발 주기를 반복할 때 유용하며, 통합 테스트는 실제 환경과의 상호작용을 검증하는 데 필수적입니다.
반응형
'Java' 카테고리의 다른 글
[JAVA] Spring Boot 대규모 트래픽 처리 #Redis #Scheduler (2) | 2025.01.14 |
---|---|
[JAVA] Spring 테스트 : Mock VS MockBean (2) | 2025.01.13 |
[JAVA] ArrayList vs LinkedList 완벽 정리 (0) | 2024.12.31 |
[JAVA] PriorityQueue 설명 및 사용법 (0) | 2024.12.30 |
[JAVA] Queue와 Deque 무엇이 좋을까? (2) | 2024.12.27 |