Mocking org.springframework.web.reactive.function.client.Web



考虑以下代码:

public Mono<Void> doStuff() {
return this.requestStuff()
.onStatus(HttpStatus::is5xxServerError,
clientResponse -> {
aMethodIWouldLikeToTest(clientResponse);
return Mono.error(new MyCustomException("First error I would like to test"));
})
.onStatus(HttpStatus::is4xxClientError,
clientResponse -> {
aMethodIWouldLikeToTest(clientResponse);
return Mono.error(new MyCustomException("Second error I would like to test"));
})
.bodyToMono(String.class)
.flatMap(x -> anotherMethodIManagedToTest(x)))
}

我的第一个目标是测试另一个使用以下命令实现的MethodIManagedToTest(x(:

import org.springframework.web.reactive.function.client.WebClient;
...
@Mock
private WebClient.ResponseSpec responseSpec;
private String desiredInputParam = "There is another black spot on the sun today!";
...
@Test
public void allGood_anotherMethodIManagedToTest_success {
...
ClassUnderTest classUnderTest = new classUnderTest()
ClassUnderTest classUnderTestSpy = spy(classUnderTestSpy);
doReturn(responseSpec).when(classUnderTestSpy).requestStuff();
when(responseSpec.onStatus(any(), any())).thenReturn(responseSpec);
when(responseSpec.bodyToMono(String.class)).thenReturn(Mono.just(desiredInputParam));
Mono<Void> result = classUnderTestSpy.doStuff();
// Bunch of assertions for anotherMethodIManagedToTest(String desiredInputParam) performed with success ...
}

现在我想创建其他测试来测试 5xxServerError 事件和 4xxClientError 事件,但我很难弄清楚如何:

  • 模拟HttpStatus::is5xxServerError的响应
  • 模拟HttpStatus::is4xxServerError的响应
  • 模拟客户端响应以测试aMethodIWouldLikeToTest(org.springframework.web.reactive.function.client.ClientResponse clientResponse(

关于如何执行这些操作的任何建议?

请注意,我不能真正使用任何PowerMock替代品(如果这是实现我的目标的唯一方法,仍然感兴趣(所有带有标准Mockito的答案都是首选。

我很抱歉我迟到了。 可以将 mockito 用于您的测试用例:

  • 你需要获取 HttpStatus 才能在 onStatus 方法中检查它
  • 所以首先创建一个实现WebClient.ResponseSpec的抽象类(以避免实现所有方法(
  • 您可以从此类而不是响应规范创建模拟
  • 我在此类中添加了 2 个方法:
abstract class CustomMinimalForTestResponseSpec implements WebClient.ResponseSpec {
public abstract HttpStatus getStatus();
public WebClient.ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate, Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {
if (statusPredicate.test(this.getStatus())) exceptionFunction.apply(ClientResponse.create(HttpStatus.OK).build()).block();
return this;
}
}
  • getStatus 将用于设置 HttpStatus:
when(responseSpecMock.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR);
  • 对于 onStatus,你可以调用 real 方法:
when(responseSpecMock.onStatus(any(Predicate.class),any(Function.class)))
.thenCallRealMethod();
  • 这是测试类:
package com.example.test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.util.function.Function;
import java.util.function.Predicate;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class ExperimentalWebClientTest {
@Mock
private WebClient webClientMock;
@InjectMocks
private ExperimentalWebClient experimentalWebClient;
@Mock
private WebClient.RequestHeadersUriSpec requestHeadersUriSpecMock;
@Mock
private WebClient.RequestHeadersSpec requestHeadersSpecMock;
@Mock
private CustomMinimalForTestResponseSpec responseSpecMock;
@Test
void shouldFailsWhenHttpStatus5xx() {
//given
when(webClientMock.get()).thenReturn(requestHeadersUriSpecMock);
when(requestHeadersUriSpecMock.uri(any(Function.class)))
.thenReturn(requestHeadersSpecMock);
when(requestHeadersSpecMock.retrieve()).thenReturn(responseSpecMock);
when(responseSpecMock.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR);
when(responseSpecMock.onStatus(any(Predicate.class), any(Function.class))).thenCallRealMethod();
//when + Then
assertThrows(MyCustomException.class,
() -> experimentalWebClient.doStuff(),
"call fails with Internal Server Error") ;
}

abstract class CustomMinimalForTestResponseSpec implements WebClient.ResponseSpec {
public abstract HttpStatus getStatus();
public WebClient.ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate, Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {
if (statusPredicate.test(this.getStatus())) exceptionFunction.apply(ClientResponse.create(HttpStatus.OK).build()).block();
return this;
}
}
}

我认为我的问题的答案是Mockito不是测试这种东西的正确工具。使用wiremock似乎是方便的方法

当我主要使用以下库进行测试时:

  • import com.github.tomakehurst.wiremock.client.WireMock;
  • import org.springframework.test.context.junit4.SpringRunner;
  • import org.springframework.boot.test.context.SpringBootTest;
  • import org.springframework.test.web.reactive.server.WebTestClient;

我设法完成了工作。

如果您遇到类似的问题,我建议您查看 https://www.sudoinit5.com/post/spring-boot-testing-consumer/,提供的示例类似于我为完成测试所做的工作。

但是,如果有人知道用Mockito完成这个问题的方法,我仍然感兴趣。

相关内容

最新更新