[英]Writing blocking operations in reactor tests with Spring and State Machine
我對反應堆編程完全陌生,自從升級到最新的 Spring Boot / State 機器后,我真的很難遷移舊的集成測試。 大多數集成測試具有相同的基本步驟:
Mono
的方法並啟動一個 state 機器並返回一個 object,其中包含生成的唯一id
以及與初始請求相關的一些其他信息。下面是一個例子:
@Test
void testEndToEnd() {
var instance = ServiceInstance.buildDefault();
var updateRequest = UpdateRequest.build(instance);
// retrieve an update Response related to the request
// since a unique id is generated when triggering the update request
// before starting a stateMachine that goes through different steps
var updateResponse = service.updateInstance(updateRequest).block();
await().alias("Check if operation was successful")
.atMost(Duration.ofSeconds(120))
.pollInterval(Duration.ofSeconds(2))
.until(() -> expectOperationState(updateResponse, OperationState.SUCCESS))
// check if values are updated in secondary table
assertValuesInTransaction(updateResponse);
}
這之前工作正常,但自從最近的更新失敗后出現異常:
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread parallel-6
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83)
at reactor.core.publisher.Mono.block(Mono.java:1710)
我看到了使用StepVerifier
測試反應器方法的好習慣,但我看不到如何重現使用Awaitability
完成的部分以輪詢以查看數據庫中的值是否已更改,因為檢查數據庫的方法返回Mono
和不是不斷發送值的流量。
關於如何完成此操作或使 spring 堆棧接受阻塞操作的任何想法?
謝謝
我目前的堆棧:
因此,正如評論中所討論的,這里是一個帶有評論的示例。 我使用flatMap
來訂閱expectOperationState
返回的內容。 還有Mono.fromCallable
使用它檢查某個方法的值,如果它在 3 秒內沒有發出任何東西 - 超時異常被拋出。 我們也可以嘗試從expectOperationState
中刪除這個boolean
值,並將代碼重構為只返回帶有完成信號的Mono<Void>
,但這基本上顯示了如何實現你想要的。
class TestStateMachine {
@Test
void testUntilSomeOperationCompletes() {
final Service service = new Service();
final UpdateRequest updateRequest = new UpdateRequest();
StepVerifier.create(service.updateInstance(updateRequest)
.flatMap(updateResponse -> expectOperationState(updateResponse, OperationState.SUCCESS))
)
.consumeNextWith(Assertions::assertTrue)
.verifyComplete();
}
private Mono<Boolean> expectOperationState(final UpdateResponse updateResponse, final OperationState success) {
return Mono.fromCallable(() -> {
while (true) {
boolean isInDb = checkValueFromDb(updateResponse);
if (isInDb) {
return true;
}
}
})
.publishOn(Schedulers.single())
//timeout if we not receive any value from callable within 3 seconds so that we do not check forever
.timeout(Duration.ofSeconds(3));
}
private boolean checkValueFromDb(final UpdateResponse updateResponse) {
return true;
}
}
class Service {
Mono<UpdateResponse> updateInstance(final UpdateRequest updateRequest) {
return Mono.just(new UpdateResponse());
}
}
這是一個不使用Mono<Boolean>
的例子:
class TestStateMachine {
@Test
void test() {
final Service service = new Service();
final UpdateRequest updateRequest = new UpdateRequest();
StepVerifier.create(service.updateInstance(updateRequest)
.flatMap(updateResponse -> expectOperationState(updateResponse, OperationState.SUCCESS).timeout(Duration.ofSeconds(3)))
)
.verifyComplete();
}
private Mono<Void> expectOperationState(final UpdateResponse updateResponse, final OperationState success) {
return Mono.fromCallable(() -> {
while (true) {
boolean isInDb = checkValueFromDb(updateResponse);
if (isInDb) {
//return completed Mono
return Mono.<Void>empty();
}
}
})
.publishOn(Schedulers.single())
//timeout if we not receive any value from callable within 3 seconds so that we do not check forever
.timeout(Duration.ofSeconds(3))
.flatMap(objectMono -> objectMono);
}
private boolean checkValueFromDb(final UpdateResponse updateResponse) {
return true;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.