Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 带有合并单元测试的Spring反应式WebClient不会终止_Java_Spring Boot_Junit_Reactive Programming_Spring Webflux - Fatal编程技术网

Java 带有合并单元测试的Spring反应式WebClient不会终止

Java 带有合并单元测试的Spring反应式WebClient不会终止,java,spring-boot,junit,reactive-programming,spring-webflux,Java,Spring Boot,Junit,Reactive Programming,Spring Webflux,我正在试验反应式Spring和WebClient,特别是尝试同时调用不同的客户端,并最终合并结果。也许事先分享很重要,可以预期其中一个服务并不总是返回值 所以我有一个简单的服务: @Service @Slf4j public class PersonSearchService { public static final String PERSON_SERVICE = "/persons"; public static final String FELLOW_

我正在试验反应式Spring和WebClient,特别是尝试同时调用不同的客户端,并最终合并结果。也许事先分享很重要,可以预期其中一个服务并不总是返回值

所以我有一个简单的服务:

@Service
@Slf4j
public class PersonSearchService {

    public static final String PERSON_SERVICE = "/persons";
    public static final String FELLOW_SERVICE = "/fellows";

    private final WebClient webClient;

    public PersonSearchService(@Value("${base.url}") String baseUrl) {
        this.webClient = WebClient.builder()
            .baseUrl(baseUrl)
            .build();
    }
    
    // This method is called from a controller where a SearchCriteria is being passed - Not important
    public Flux<PersonResult> getPeople(SearchCriteria search) {
        return Flux.merge(
            getPeople(PERSON_SERVICE, search),
            getPeople(FELLOW_SERVICE, search));
    }

    private Flux<PersonResult> getPeople(String path, SearchCriteria search) {
        
        return webClient.get()
            .uri(path, search)
            .accept(MediaType.APPLICATION_JSON)
            .retrieve()
            .onStatus(HttpStatus::isError, ErrorHandler::handleError)
            .bodyToFlux(PersonResult.class);
    }
}
因此,这正如预期的那样工作,但当我尝试对其进行单元测试时,我的测试从未终止(连接保持活动状态)。这是我的测试:

@ExtendWith(MockitoExtension.class)
class PersonSearchServiceTest {

    private ObjectMapper objectMapper;
    private MockWebServer mockWebServer;
    private PersonSearchServiceTest personSearchService;

    @BeforeEach
    void setUp() {
        objectMapper = new ObjectMapper();
        mockWebServer = new MockWebServer();
        personSearchService = new PersonSearchServiceTest(mockWebServer.url("localhost").toString());
    }

    @AfterEach
    void tearDown() throws IOException {
        mockWebServer.shutdown();
    }

    @Test
    void getPeople_empty() {
        mockWebServer.enqueue(new MockResponse()
            .setResponseCode(200)
            .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
            .setBody("[]"));

        SearchCriteria search = SearchCriteria.builder().build();

        Flux<PersonResult> resultFlux = personSearchService.getPeople(search);

        StepVerifier.create(resultFlux)
            .expectNextCount(0)
            .verifyComplete();

//
//        assertThat(this.personSearchService.getPeople(search).collectList().block())
//            .isEqualTo(Collections.emptyList());
    }

    @Test
    void getDataPlanParcels() throws Exception {
        var person = PersonResult.builder()
            .id("1234")
            .age(20)
            .build();

        mockWebServer.enqueue(new MockResponse()
            .setResponseCode(200)
            .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
            .setBody(objectMapper.writeValueAsString(person)));

        SearchCriteria search = Search.builder().build();
        Flux<PersonResult> resultFlux = personSearchService.getPeople(search);

        StepVerifier.create(resultFlux)
            .expectNextMatches(result -> result.getId().equals("1234"))
            .verifyComplete();
    }

}
@ExtendWith(MockitoExtension.class)
班级人员搜索服务测试{
私有对象映射器对象映射器;
私有MockWebServer MockWebServer;
私人搜索服务测试人员搜索服务;
@之前
无效设置(){
objectMapper=新的objectMapper();
mockWebServer=新建mockWebServer();
personSearchService=newPersonSearchServiceTest(mockWebServer.url(“localhost”).toString());
}
@之后
void tearDown()引发IOException{
mockWebServer.shutdown();
}
@试验
void getPeople_empty(){
mockWebServer.enqueue(新的MockResponse()
.setResponseCode(200)
.setHeader(HttpHeaders.CONTENT\u TYPE、MediaType.APPLICATION\u JSON)
.立位体(“[]”);
SearchCriteria search=SearchCriteria.builder().build();
Flux resultFlux=personSearchService.getPeople(搜索);
StepVerifier.create(resultFlux)
.expectNextCount(0)
.verifyComplete();
//
//assertThat(this.personSearchService.getPeople(search.collectList().block())
//.isEqualTo(Collections.emptyList());
}
@试验
void getDataPlanParcels()引发异常{
var person=PersonResult.builder()
.id(“1234”)
.年龄(20岁)
.build();
mockWebServer.enqueue(新的MockResponse()
.setResponseCode(200)
.setHeader(HttpHeaders.CONTENT\u TYPE、MediaType.APPLICATION\u JSON)
.setBody(objectMapper.writeValueAsString(person));
SearchCriteria search=search.builder().build();
Flux resultFlux=personSearchService.getPeople(搜索);
StepVerifier.create(resultFlux)
.expectNextMatches(结果->结果.getId().equals(“1234”))
.verifyComplete();
}
}
上述两个测试中的任何一个都不会终止并等待,这是我在终端中看到的:

00:07:09.209 [reactor-http-epoll-3] DEBUG r.n.http.client.HttpClientOperations.debug(244) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] Received last HTTP packet <no request,no span> 
00:07:09.218 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(249) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] onStateChange(GET{uri=/localhost/license-service/v3/ACPMDE/parcels/search, connection=PooledConnection{channel=[id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281]}}, [response_completed]) <no request,no span> 
00:07:09.220 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(249) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] onStateChange(GET{uri=/localhost/license-service/v3/ACPMDE/parcels/search, connection=PooledConnection{channel=[id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281]}}, [disconnecting]) <no request,no span> 
00:07:09.220 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(244) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] Releasing channel <no request,no span> 
00:07:09.224 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(249) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] Channel cleaned, now 1 active connections and 1 inactive connections <no request,no span> 
00:07:09.209[reactor-http-epoll-3]调试r.n.http.client.HttpClientOperations.DEBUG(244)-[id:0xee38099d,L:/127.0.0.1:49742-r:localhost/127.0.0.1:43281]收到最后一个http数据包
00:07:09.218[reactor-http-epoll-3]调试r.n.r.DefaultPooledConnectionProvider.DEBUG(249)-[id:0xee38099d,L:/127.0.0.1:49742-r:localhost/127.0.0.1:43281]onStateChange(获取{uri=/localhost/license service/v3/ACPMDE/parcels/search,connection=PooledConnection{通道=[id:0xee38099d,L:/127.0.0.0.1:49742-r:localhost/127.0.0.1:431},[答复已完成])
00:07:09.220[reactor-http-epoll-3]调试r.n.r.DefaultPooledConnectionProvider.DEBUG(249)-[id:0xee38099d,L:/127.0.0.1:49742-r:localhost/127.0.0.1:43281]onStateChange(获取{uri=/localhost/license service/v3/ACPMDE/parcels/search,connection=PooledConnection{channel=[id:0xee38099d,L:/127.0.0.1:49742-r:localhost/127.0.0.0.1:43281},[断开连接])
00:07:09.220[reactor-http-epoll-3]调试r.n.r.DefaultPooledConnectionProvider.DEBUG(244)-[id:0xee38099d,L:/127.0.0.1:49742-r:localhost/127.0.0.1:43281]释放通道
00:07:09.224[reactor-http-epoll-3]调试r.n.r.DefaultPooledConnectionProvider.DEBUG(249)-[id:0xee38099d,L:/127.0.0.1:49742-r:localhost/127.0.0.1:43281]通道已清理,现在有1个活动连接和1个非活动连接
我的测试设置有问题吗?还是需要在WewbClient上进行额外的配置?
如果我删除了
Flux.merge
或者只有一个源,那么测试是绿色的。

在我看来,您只在模拟服务器上设置了一个响应。因此,第一个调用进行得很顺利,然后第二个调用进行,服务器正在等待来自模拟服务器的响应。因此,如果您等待的时间足够长,它可能会超时。因此,可能
排队两个响应。是的,我想测试只有一个响应时会发生什么。也就是说,在“真实”中也可能发生这种情况life-这些服务中只有一个可以提供基于
搜索
的响应,而另一个没有匹配项。理想情况下,如果
搜索
调用没有匹配项,您仍然会收到一个响应,指示
搜索
api没有找到传入的搜索条件的响应。如果要模拟无响应,请nse那么你应该在你的web客户端上设置一个读取超时,并提供一个合适的
onError
操作符来处理该故障。是的,即使找不到任何响应,这两个服务也会提供响应。我使用Wiremock服务器而不是okhttp Mock web服务器,我没有相同的问题。因此,这必须是与我的测试设置相关,但我不想对每个服务都显式地执行
enqueue
00:07:09.209 [reactor-http-epoll-3] DEBUG r.n.http.client.HttpClientOperations.debug(244) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] Received last HTTP packet <no request,no span> 
00:07:09.218 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(249) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] onStateChange(GET{uri=/localhost/license-service/v3/ACPMDE/parcels/search, connection=PooledConnection{channel=[id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281]}}, [response_completed]) <no request,no span> 
00:07:09.220 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(249) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] onStateChange(GET{uri=/localhost/license-service/v3/ACPMDE/parcels/search, connection=PooledConnection{channel=[id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281]}}, [disconnecting]) <no request,no span> 
00:07:09.220 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(244) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] Releasing channel <no request,no span> 
00:07:09.224 [reactor-http-epoll-3] DEBUG r.n.r.DefaultPooledConnectionProvider.debug(249) - [id: 0xee38099d, L:/127.0.0.1:49742 - R:localhost/127.0.0.1:43281] Channel cleaned, now 1 active connections and 1 inactive connections <no request,no span>