模拟RxJava异步http调用

模拟RxJava异步http调用,java,junit,mockito,rx-java,Java,Junit,Mockito,Rx Java,我在模拟RxJava函数时遇到了一些麻烦,该函数会进行一些HTTP调用。我正在使用JUnit和Mockito //Customer.java extends ServiceManager public Observable<String> getCustomerDetails(String uuidData){ String api = "http://someapi.com/" + uuidData; return callHttps(api, getHeader(

我在模拟RxJava函数时遇到了一些麻烦,该函数会进行一些HTTP调用。我正在使用JUnit和Mockito

//Customer.java extends ServiceManager
public Observable<String> getCustomerDetails(String uuidData){
    String api = "http://someapi.com/" + uuidData;
    return callHttps(api, getHeader(),
            "",
            HttpMethod.GET)
            .doOnError(failure -> logger.error("Error was raised while calling Profile Save of ORCH API:"
                    + failure.getMessage()))
            .doOnNext(httpClientResponse -> {
                logger.info("");
            })
            .concatMap(RxHelper::toObservable)
            .reduce(Buffer.buffer(), Buffer::appendBuffer)
            .map(buffer -> buffer.toString("UTF-8"))
            .map(entries -> entries);
}

private MultiMap getProfileHeader(){
    MultiMap headers = MultiMap.caseInsensitiveMultiMap();
    headers.add("Accept","application/json");
    return headers;
}


public class ServiceManager {
    @Inject
    @Named("httpsClient")
    private HttpClient httpsClient;

    private static final Logger logger = LoggerFactory.getLogger(ServiceManager.class);

    public Observable<HttpClientResponse> callHttps(String url, MultiMap headers, String body, HttpMethod httpMethod) {
        return Observable.create(subscriber -> {
            HttpClientRequest httpClientRequest = httpsClient.requestAbs(httpMethod, url);
            httpClientRequest.exceptionHandler(event -> {
               logger.error("Exception was raised :" + event.getMessage());
            });
            httpClientRequest.headers().addAll(headers);
            RxHelper
                    .toObservable(httpClientRequest)
                    .subscribe(subscriber);

            httpClientRequest.end(body);
        });
    }
}
//Customer.java扩展了ServiceManager
公共可观察的getCustomerDetails(字符串uuidData){
字符串api=”http://someapi.com/“+uuidData;
返回callHttps(api,getHeader(),
"",
HttpMethod.GET)
.doError(失败->记录器.error(“调用ORCH API的配置文件保存时引发错误:”
+失败。getMessage()))
.doOnNext(httpClientResponse->{
logger.info(“”);
})
.concatMap(RxHelper::toObservable)
.reduce(Buffer.Buffer(),Buffer::appendBuffer)
.map(buffer->buffer.toString(“UTF-8”))
.map(条目->条目);
}
私有多映射getProfileHeader(){
MultiMap headers=MultiMap.caseinsensitivimultimap();
添加(“接受”、“应用程序/json”);
返回标题;
}
公共类服务管理器{
@注入
@命名(“httpsClient”)
私有HttpClient HttpScClient;
私有静态最终记录器Logger=LoggerFactory.getLogger(ServiceManager.class);
公共可观察调用HTTPS(字符串url、多映射头、字符串正文、HttpMethod HttpMethod){
返回可观察。创建(订户->{
HttpClientRequest HttpClientRequest=HttpScClient.requestAbs(httpMethod,url);
httpClientRequest.exceptionHandler(事件->{
logger.error(“引发异常:+event.getMessage());
});
httpClientRequest.headers().addAll(headers);
RxHelper
.toObservable(httpClientRequest)
.认购(认购人);
httpClientRequest.end(正文);
});
}
}

如何模拟
callHttps
函数,使其返回
HttpClientRequest
模拟响应。我的另一种方法是使用WireMock,但我想通过模拟上述函数找到一种方法。

假设
Customer
不必是final,您可以使用。基本上,在这个模式中,您可以扩展被测试的类,以使用新的模拟功能覆盖方法。因此,您可以扩展
Customer
并覆盖
callHttps()
,这样它实际上除了记录调用它之外什么都不做,这样您就可以验证它是否确实被调用了

请注意,我并不主张您应该像这样测试代码。通常情况下,使用此模式表示。因此,如果可以的话,完全放弃继承权。也就是说,如果必须,请尝试使用类似于以下示例代码的代码:

public class CustomerTest {
  @Mock
  private Observable<HttpClientResponse> mockObservable;

  @Before
  public void setup() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void getCustomerDetailsCallsCallHttps() {
    CustomerSelfShunt customerUnderTest = new CustomerSelfShunt();
    // Call the getCustomerDetails method. Should call overridden version of
    // callHttps() that sets callHttpsInvoked.
    Observable<String> actualObservable = customerUnderTest.getCustomerDetails("foo");
    assertEquals(this.mockObservable, actualObservable);
    assertTrue(customerUnderTest.callHttpsInvoked);
  }

  private class CustomerSelfShunt extends Customer {
    boolean callHttpsInvoked = false;

    public Observable<HttpClientResponse> callHttps(String url, MultiMap headers, String body, HttpMethod httpMethod) {
      // do nothing implementation, just record that this method was called.
      callHttpsInvoked = true;
    }
  }
}
公共类客户测试{
@嘲弄
私人可观察的或可观察的;
@以前
公共作废设置(){
initMocks(this);
}
@试验
public void getCustomerDetailsCallsCallHttps(){
CustomerSelfShuttle customerUnderTest=新CustomerSelfShuttle();
//调用getCustomerDetails方法。应调用
//callHttps(),用于设置callHttpsInvoked。
Observable ActualObjectable=customerUnderTest.getCustomerDetails(“foo”);
assertEquals(this.mockObservable,actualObservable);
assertTrue(customerUnderTest.callHttpsInvoked);
}
私有类CustomerSelf扩展了Customer{
布尔callHttpSinvoke=false;
公共可观察调用HTTPS(字符串url、多映射头、字符串正文、HttpMethod HttpMethod){
//不执行任何实现,只记录调用了此方法。
callHttpsInvoked=true;
}
}
}

假设
客户
不必是最终客户,您可以使用。基本上,在这个模式中,您可以扩展被测试的类,以使用新的模拟功能覆盖方法。因此,您可以扩展
Customer
并覆盖
callHttps()
,这样它实际上除了记录调用它之外什么都不做,这样您就可以验证它是否确实被调用了

请注意,我并不主张您应该像这样测试代码。通常情况下,使用此模式表示。因此,如果可以的话,完全放弃继承权。也就是说,如果必须,请尝试使用类似于以下示例代码的代码:

public class CustomerTest {
  @Mock
  private Observable<HttpClientResponse> mockObservable;

  @Before
  public void setup() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void getCustomerDetailsCallsCallHttps() {
    CustomerSelfShunt customerUnderTest = new CustomerSelfShunt();
    // Call the getCustomerDetails method. Should call overridden version of
    // callHttps() that sets callHttpsInvoked.
    Observable<String> actualObservable = customerUnderTest.getCustomerDetails("foo");
    assertEquals(this.mockObservable, actualObservable);
    assertTrue(customerUnderTest.callHttpsInvoked);
  }

  private class CustomerSelfShunt extends Customer {
    boolean callHttpsInvoked = false;

    public Observable<HttpClientResponse> callHttps(String url, MultiMap headers, String body, HttpMethod httpMethod) {
      // do nothing implementation, just record that this method was called.
      callHttpsInvoked = true;
    }
  }
}
公共类客户测试{
@嘲弄
私人可观察的或可观察的;
@以前
公共作废设置(){
initMocks(this);
}
@试验
public void getCustomerDetailsCallsCallHttps(){
CustomerSelfShuttle customerUnderTest=新CustomerSelfShuttle();
//调用getCustomerDetails方法。应调用
//callHttps(),用于设置callHttpsInvoked。
Observable ActualObjectable=customerUnderTest.getCustomerDetails(“foo”);
assertEquals(this.mockObservable,actualObservable);
assertTrue(customerUnderTest.callHttpsInvoked);
}
私有类CustomerSelf扩展了Customer{
布尔callHttpSinvoke=false;
公共可观察调用HTTPS(字符串url、多映射头、字符串正文、HttpMethod HttpMethod){
//不执行任何实现,只记录调用了此方法。
callHttpsInvoked=true;
}
}
}
一些选项:

  • 莫基托提供间谍设施来协助处理这种情况。(尽管它的使用通常表示应该重新构造代码)
  • 示例(简化-在本例中,我不得不模拟HttpClientResponse,因为我无法创建具体实例-但至少可以避免模拟Observable):

    package com.sbp;
    导入静态org.junit.Assert.assertEquals;
    导入静态org.mockito.Matchers.any;
    导入静态org.mockito.Matchers.anyString;
    导入静态org.mockito.mockito.mock;
    导入静态org.mockito.mockito.when;
    导入静态rx.Observable.just;
    导入io.vertx.core.MultiMap;
    导入io.vertx.core.http.HttpClientResponse;
    导入org.junit.Test;
    导入org.junit.runner.RunWith;
    导入org.mockito.Spy;
    导入org.mockito.runners.MockitoJUnitRunner;
    英普