https://docs.spring.io/spring-modulith/reference/testing.html
@ApplicationModuleTest 애너테이션을 달면 된다.package example.order
@ApplicationModuleTest
class OrderIntegrationTests {
// Individual test cases go here
}
@SpringBootTest와 유사한 통합 테스트가 실행된다.
org.springframework.modulith=DEBUG로 설정하면 스프링부트 부트스트랩을 정의하는 방법에 대한 자세한 정보를 알 수 있다.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.0-SNAPSHOT)
… - Bootstrapping @ApplicationModuleTest for example.order in mode STANDALONE (class example.Application)…
… - ======================================================================================================
… - ## example.order ##
… - > Logical name: order
… - > Base package: example.order
… - > Direct module dependencies: none
… - > Spring beans:
… - + ….OrderManagement
… - + ….internal.OrderInternal
… - Starting OrderIntegrationTests using Java 17.0.3 …
… - No active profile set, falling back to 1 default profile: "default"
… - Re-configuring auto-configuration and entity scan packages to: example.order.
STANDALONE (default) - 현재 모듈만 수행DIRECT_DEPENDENCIES - 현재 모듈 그리고 직접적인 의존이 있는 모듈만 수행ALL_DEPENDENCIES - 의존 관계가 있는 전체 모듈 트리에 대해 수행@MockBean 사용TransactionOperations 및 ApplicationEventProcessor - 트랜잭션 리스너에 이벤트가 게시되고 전달되는지 확인Awaitility - 동시성 처리Scenario 추상화를 제공한다.
@ApplicationModuleTest로 선언된 테스트에서 메서드 파라미터로 사용 가능@ApplicationModuleTest
class SomeApplicationModuleTest {
@Test
fun someModuleIntegrationTest(scenario: Scenario) {
// Use the Scenario API to define your integration test
}
}
Scenario는 이러한 단계를 정의하고 안내하는 API를 제공한다.// Start with an event publication
scenario.publish(MyApplicationEvent(…)).…
// Start with a bean invocation
scenario.stimulate(() -> someBean.someMethod(…)).…
…customize(…) 메서드를 통해 실행을 커스터마이징하거나 타임아웃 설정을 위한 특수 메서드 (…waitAtMost(…))를 통해 커스터마이징 할 수 있다.SomeOtherEvent가 발행되거나 타임아웃 될 때까지 실행이 차단된다.….andWaitForEventOfType(SomeOtherEvent.class)
.matching(event -> …) // Use some predicate here
.…
…toArrive…()
// Executes the scenario
….toArrive(…)
// Execute and define assertions on the event received
….toArriveAndVerify(event -> …)
scenario.publish(new MyApplicationEvent(…))
.andWaitForEventOfType(SomeOtherEvent::class)
.matching(event -> …)
.toArriveAndVerify(event -> …)
…andVerify(…) 메서드로 전달된 결과다.scenario.publish(new MyApplicationEvent(…))
.andWaitForStateChange(() -> someBean.someMethod(…)))
.andVerify(result -> …)
non-null 값과 empty가 아닌 Optional 값은 결정적인 상태 변경으로 간주된다.
…andWaitForStateChange(…, Predicate)로 조정할 수 있다.Scenario를 커스터마이징 하려면 customize(…) 메서드를 호출하면 된다.scenario.publish(MyApplicationEvent(…))
.customize(it -> it.atMost(Duration.ofSeconds(2)))
.andWaitForEventOfType(SomeOtherEvent::class)
.matching(event -> …)
.toArriveAndVerify(event -> …)
Senario 인스턴스를 전역적으로 사용하는 방법도 존재한다.@ExtendWith(MyCustomizer::class)
class MyTests {
@Test
fun myTestCase(scenario : Scenario) {
// scenario will be pre-customized with logic defined in MyCustomizer
}
class MyCustomizer : ScenarioCustomizer {
override fun getDefaultCustomizer(method : Method, context : ApplicationContext) : Function<ConditionFactory, ConditionFactory> {
return it -> …
}
}
}