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 -> …
}
}
}