簡體   English   中英

使用 Spring 和 State 機器在反應堆測試中編寫阻塞操作

[英]Writing blocking operations in reactor tests with Spring and State Machine

我對反應堆編程完全陌生,自從升級到最新的 Spring Boot / State 機器后,我真的很難遷移舊的集成測試。 大多數集成測試具有相同的基本步驟:

  1. 調用一個返回Mono的方法並啟動一個 state 機器並返回一個 object,其中包含生成的唯一id以及與初始請求相關的一些其他信息。
  2. 使用返回的 object 調用一個方法來驗證數據庫中的值是否已更新(使用在步驟 1 中重試的 object 的信息)
  3. 以固定時間間隔輪詢在數據庫中檢查值是否已更改的方法,直到值已更改或發生預定義的超時。
  4. 查看數據庫中的另一張表是否已更新另一個 object

下面是一個例子:

    @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 堆棧接受阻塞操作的任何想法?

謝謝

我目前的堆棧:

  • Spring 啟動 3.0.1
  • Spring State 機器 3.0.1
  • Spring 6
  • Junit 5.9.2

因此,正如評論中所討論的,這里是一個帶有評論的示例。 我使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM