@TestConfiguration의 사용은 이 리뷰에서 시작된다.
바우처 미션
은 JPA를 사용하지 않고 JDBC로 구현되기 때문에 key를 직접 생성해줘야 했다.
나는 랜덤값
으로 생성되도록 선택했는데 ( 추후에는 UUID 중에서 정렬이 가능한 UUID를 선택했지만 이 내용에 관해서는 추후에 다루어볼 예정이다.) 서브멘토님께서 이 부분에 대해서 계속 무언가 힌트를 주셨었다.
따라서 아래의 물음에서 시작된다.
정해진 숫자를 넣어서 만들 수 있는지를 테스트하고 싶다면 어떻게 할 것인가?
내가 쉽게 답을 찾지 못해서 직접적인 방향성을 제시해 주셨다.
바로 interface
로 만들어서
하나는 운영할 때, 하나는 테스트할 때 사용할 수 있도록 구현하는 것이다.
import java.time.LocalDateTime;
public interface Generator {
String makeKey();
LocalDateTime makeDate();
}
하나는 실제 비즈니스에서 사용하고
@Component
public class GeneratorImp implements Generator {
@Override
public String makeKey() {
UUID generateId = Generators.timeBasedGenerator().generate();
String[] idArr = generateId.toString().split("-");
return idArr[2]+"-"+idArr[1]+"-"+idArr[0]+"-"+idArr[3]+"-"+idArr[4] ;
}
@Override
public LocalDateTime makeDate() {
return LocalDateTime.now();
}
}
다른 하나는 테스트할 때 사용한다. 아래와 같이 직접 입력된 값으로
public class TestGeneratorImp implements Generator {
@Override
public String makeKey() {
return "22";
}
@Override
public LocalDateTime makeDate() {
String str = "2023-07-29 13:47:13.248";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
return LocalDateTime.parse(str, formatter);
}
}
근데 위 코드를 보고 아래와 같은 의문이 생길 수 있다.
TestGeneratorImp를 빈으로 등록하지 않았는데 테스트할 때
어떻게 인터페이스를 통해서 가져올 것이며 등록했다 하더라도
같은 종류의 빈이 2개 등록되어 있는데 어떻게 테스트를 위한 빈을 우선적으로 가져올 것인가? 🤔
어떤 사람은@Primary
를 이용하여 하면되지 라고 말할 수 있다.
그러면 이 과정이 필요하다.
TestGeneratorImp를 빈으로 등록
테스트할 때 이 빈을 사용하기 위해서 TestGeneratorImp에 들억가서 @Primary
를 넣어준다
실제 코드에서 필요하지 않은 테스트 빈이 등록되어 있다.
테스트 할 때마다 가서 @Primary
를 넣어줘야 한다. 그러나 만약에 내가 이걸 잊어버리고 안 지운다면?
따라서 이러한 단점을 해결해주는 것이 @TestConfiguration
이었다.
Config 파일을 test 폴더 아래에 만들어준다.
Config 파일에서 @TestConfiguration을 통해서 내가 테스트 시 사용하고자 하는 빈을 만들어 등록한다.
그러면 테스트할 때 Generator로 등록된 두 개의 빈(TestConfig, GeneratorImp) 중에서 내가 @TestConfiguration으로 등록한 빈을 우선적으로 선택한다.
import com.prgrms.common.util.Generator;
import com.prgrms.common.util.TestGeneratorImp;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
@TestConfiguration
public class TestConfig {
@Bean
Generator generator() {
return new TestGeneratorImp();
}
}
그리고 마지막으로 @Import를 통해서 테스트할 때 직접적으로 빈을 가져와야 한다.
@Transactional
@SpringBootTest
@Import({TestConfig.class})
class VoucherServiceTest {
마지막으로 정말 내가 주입하고자 하는 빈이 주입되었는지 디버그로 확인해보자.
@Transactional
@SpringBootTest
@Import({TestConfig.class})
class VoucherServiceTest {
final static String FIXED_ID = "22";
final static String PERCENT_ID = "40";
final static double DISCOUNT_AMOUNT = 20;
@Autowired
VoucherService voucherService;
@Autowired
VoucherRepository voucherRepository;
@Test
@DisplayName("만들고자 하는 바우처를 createVoucher()로 만들었을 때 기대값과 같은 바우처를 반환한다.")
void createVoucher_RepositoryInsertVoucher_Equals() {
//given
VoucherType voucherType = VoucherType.FIXED_AMOUNT_VOUCHER;
Discount discount = new FixedDiscount(DISCOUNT_AMOUNT);
VoucherServiceCreateRequest serviceCreateRequest = new VoucherServiceCreateRequest(voucherType,DISCOUNT_AMOUNT);
//when
VoucherServiceResponse result = voucherService.createVoucher(serviceCreateRequest);
//then
assertThat(result.voucherId())
.isNotNull()
.isEqualTo("22");
}
디버깅 모드를 통해서 보면 voucherService와 관계를 맺은 빈을 보면
TestGeneratorImp이 주입된 것을 확인할 수 있다.