-
[JUnit] Spring Boot 애플리케이션 테스트DEV/JUnit 2024. 12. 10. 17:33
Spring Initializr 를 이용해 Spring 프로젝트 만들기
해당 페이지에서 스프링을 구동하기 위한 최소한의 설정을 가지고 스프링 부트 프로젝트 뼈대를 만들어줌
- Explore : 생성될 프로젝트에 대한 세부정보 확인 가능
- Generate : 프로젝트가 포함된 zip파일 다운로드
JUnit5로 테스트한 Spring 애플리케이션을 Spring Boot로 전환하기
1. 패키지 구조 설정
- model : 모델 클래스 만들기
- registration : 승객 등록과 관련된 클래스 만들기
2. application-context.xml 파일의 컴포넌트 스캔 설정 제거
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="passenger" class="com.manning.junitbook.spring_boot.model.Passenger"> <constructor-arg name="name" value="John Smith"/> <property name="country" ref="country"/> <property name="isRegistered" value="false"/> </bean> <bean id="country" class="com.manning.junitbook.spring_boot.model.Country"> <constructor-arg name="name" value="USA"/> <constructor-arg name="codeName" value="US"/> </bean> </beans>
<context:component-scan base-package=".." /> 대신 애노테이션 사용
@SpringBootTest @EnableAutoConfiguration @ImportResource("classpath:application-context.xml") class RegistrationTest { @Autowired private Passenger passenger; @Autowired private RegistrationManager registrationManager; @Test void testPersonRegistration() { registrationManager.getApplicationContext().publishEvent(new PassengerRegistrationEvent(passenger)); System.out.println("After registering:"); System.out.println(passenger); assertTrue(passenger.isRegistered()); } }
- @SpringBootTest : @EnableAutoConfiguration 애노테이션과 함께 현재 테스트 클래스 패키지와 서브 패키지에서 스프링 빈을 검색한다. 해당 애노테이션이 빈을 알아서 찾아 @Autowired (객체 주입)이 가능하다
- @ImportResource : XML 설정에 여전히 데이터 빈이 존재할 경우 설정파일로부터 빈을 가져오는 애노테이션
실행결과 (성공)
Spring Boot에서 테스트 전용 구성 구현하기
xml은 전통적인 스프링 빈 구성 방식으로 외부 의존성이 필요하지 않으며 소스 코드를 다시 컴파일할 필요가 없어 바꾸기 쉽다. 그러나 Spring Boot에서 제공하는 애노테이션을 사용하여 이를 대체한다면 Java 오류를 사전에 방지할 수 있다. 설정이 잘못 되었을 경우 컴파일 오류를 띄우기 떄문에, Java 기반으로 정의된 Bean은 타입에 안전하다.
1. application-context.xml 의 기존 Bean을 @TestConfiguration 애노테이션으로 대체하기
package com.manning.junitbook.spring_boot.beans; import com.manning.junitbook.spring_boot.model.Country; import com.manning.junitbook.spring_boot.model.Passenger; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; @TestConfiguration public class TestBeans { @Bean Passenger createPassenger() { Passenger passenger = new Passenger("John Smith"); passenger.setCountry(createCountry()); passenger.setIsRegistered(false); return passenger; } @Bean Country createCountry() { Country country = new Country("USA", "US"); return country; } }
- @TestConfiguration : 빈을 정의하거나 테스트에 적용하기 위한 사용자 정의 구성에 사용할 수 있다.
- @Bean 애노테이션을 통해 해당 빈을 사용할 것을 명시
- RegistrationManager와 PassengerRegistrationListener 같은 기능 빈은 @Service로 등록한다.
- 기존의 applicaition-context.xml 은 삭제
2. RegistrationTest 클래스 수정
@SpringBootTest @Import(TestBeans.class) class RegistrationTest { ... }
- @EnableAutoConfiguration, @ImportResource로 빈을 가져오던 방식을 @Import 애노테이션으로 변경
실행결과 (동일하게 성공)
신규 기능 추가하여 Spring Boot 애플리케이션 테스트하기
: 항공편 생성 및 설정, 항공편에 승객 추가 및 삭제 기능 추가
1. Flight 클래스 생성
import java.util.Collections; import java.util.HashSet; import java.util.Set; public class Flight { private String flightNumber; private int seats; private Set<Passenger> passengers = new HashSet<>(); public Flight(String flightNumber, int seats) { this.flightNumber = flightNumber; this.seats = seats; } public String getFlightNumber() { return flightNumber; } public int getSeats() { return seats; } public Set<Passenger> getPassengers() { return Collections.unmodifiableSet(passengers); } public boolean addPassenger(Passenger passenger) { if (passengers.size() >= seats) { throw new RuntimeException("항공편의 좌석 수보다 더 많은 승객을 추가할 수 없습니다"); } return passengers.add(passenger); } public boolean removePassenger(Passenger passenger) { return passengers.remove(passenger); } @Override public String toString() { return "Flight " + getFlightNumber(); } }
- getPassenger() : unmodifiableSet을 사용하여 수정할 수 없는 승객 정보 리스트를 반환
2. 승객 리스트 CSV 생성
flights_infromation.csv
John Smith; UK Jane Underwood; AU James Perkins; US Mary Calderon; US Noah Graves; UK Jake Chavez; AU Oliver Aguilar; US Emma McCann; AU Margaret Knight; US Amelia Curry; UK Jack Vaughn; US Liam Lewis; AU Olivia Reyes; US Samantha Poole; AU Patricia Jordan; UK Robert Sherman; US Mason Burton; AU Harry Christensen; UK Jennifer Mills; US Sophia Graham; UK
3. FlightBuilder 클래스 생성
: CSV 파일을 읽어와 항공편에 승객 정보를 채워 넣음
import com.manning.junitbook.spring_boot.model.Country; import com.manning.junitbook.spring_boot.model.Flight; import com.manning.junitbook.spring_boot.model.Passenger; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; import java.util.Map; @TestConfiguration public class FlightBuilder { private static Map<String, Country> countriesMap = new HashMap<>(); static { countriesMap.put("AU", new Country("Australia", "AU")); countriesMap.put("US", new Country("USA", "US")); countriesMap.put("UK", new Country("United Kingdom", "UK")); } @Bean Flight buildFlightFromCsv() throws IOException { Flight flight = new Flight("AA1234", 20); try (BufferedReader reader = new BufferedReader(new FileReader("src/test/resources/flights_information.csv"))) { String line = null; do { line = reader.readLine(); if (line != null) { String[] passengerString = line.toString().split(";"); Passenger passenger = new Passenger(passengerString[0].trim()); passenger.setCountry(countriesMap.get(passengerString[1].trim())); passenger.setIsRegistered(false); // 승객을 미등록 상태로 설정 flight.addPassenger(passenger); // 항공편에 승객 추가 } } while (line != null); } return flight; } }
4. FlightTest 클래스 생성
: 항공편에 추가된 모든 승객을 등록하고 등록이 완료되었는지 테스트 검증
import com.manning.junitbook.spring_boot.beans.FlightBuilder; import com.manning.junitbook.spring_boot.model.Flight; import com.manning.junitbook.spring_boot.model.Passenger; import com.manning.junitbook.spring_boot.registration.PassengerRegistrationEvent; import com.manning.junitbook.spring_boot.registration.RegistrationManager; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @SpringBootTest @Import(FlightBuilder.class) public class FlightTest { @Autowired private Flight flight; @Autowired private RegistrationManager registrationManager; @Test void testFlightPassengersRegistration() { for (Passenger passenger : flight.getPassengers()) { assertFalse(passenger.isRegistered()); registrationManager.getApplicationContext().publishEvent(new PassengerRegistrationEvent(passenger)); } System.out.println("모든 승객이 등록되었는지 확인"); for (Passenger passenger : flight.getPassengers()) { assertTrue(passenger.isRegistered()); } } }
실행결과
'DEV > JUnit' 카테고리의 다른 글
[JUnit] REST API 테스트 하기 (2) 2025.01.07 [JUnit] JUnit5 extension (확장 모델) (1) 2024.10.22 [JUnit] 모의 객체 프레임워크 EasyMock / JMock / Mockito (0) 2024.09.11 [JUnit] 모의객체를 활용해 리팩터링하기 (0) 2024.08.27 [JUnit] 모의 객체로 테스트하기 (0) 2024.08.25