如何模拟 sun jersey 客户端 post 调用?
how to mock sun jersey client post calls?
这是我的代码
@Service
public class PaymentHandler {
private static final Gson GSON = new Gson();
private static Client webServiceClient = createSslClient(); // function creates a ssl connection
public Response makePayment(String payload) {
WebResource webResource = webServiceClient.resource(url);
WebResource.Builder builder = webResource.getRequestBuilder();
String r = builder
.type(MediaType.APPLICATION_JSON_TYPE)
.accept(MediaType.APPLICATION_JSON_TYPE)
.post(String.class, payload);
Response response = GSON.fromJson(r, Response.class);
}
}
这是我尝试测试它的方法,但它不起作用,它总是调用支付服务。我无法嘲笑它。
Client client = mock(Client.class );
WebResource webResource = mock(WebResource.class);
WebResource.Builder builder = mock(WebResource.Builder.class);
ClientResponse clientResponse = mock(ClientResponse.class);
when(client.resource(anyString())).thenReturn(webResource);
when(webResource.getRequestBuilder()).thenReturn(builder);
when(builder.type(anyString())).thenReturn(builder);
when(builder.accept(anyString())).thenReturn(builder);
when(builder.post(Matchers.eq(String.class), anyString())).thenReturn("Test");
paymentHandler.makePayment(payload); //assume that I send actual payload
有人可以告诉我如何模拟这个吗?
在您的测试中,我没有看到您将 webServiceClient
替换为模拟版本。
但首先,我相信你最好不要在没有依赖注入的情况下编写 PaymentHandler
这样的代码。它可能只是一个简单的组合,将 webServiceClient
注入 PaymentHandler
。没有依赖注入,它不灵活,难以维护,因此不可测试。例如,想象一下,如果初始化这样一个字段需要与外部系统进行一些交互,会发生什么情况。如果没有任何字节码操作库,您将如何测试它?或者您如何轻松地从一个 webServiceClient
迁移到另一个,例如从非 SSL 到 SSL?
尽管存在这些众所周知的问题,但有时我们不得不处理我们无法轻易更改的第 3 方或遗留代码。但是我们想为与 3rd 方代码交互的代码编写测试。出于这个确切的原因,存在一些很酷的测试框架。 PowerMock 就是其中之一,下面是使用它的工作代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest(PaymentHandler.class)
public class PaymentHandlerTest {
@Test
public void test() throws Exception {
//we don't want to initialize the PaymentHandler.class because it might cause some
//heavy undesirable initilization. E.g. if we had referred to PaymentHandler as a class
//literal here, then the webServiceClient would've been initializaed with some "real"
//instance of Client. My PaymentHandler is located in so package. You should specify your
//fully qualified class' name here
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass("so.PaymentHandler");
//now the webServiceClient will be null once we initialize the PaymentHandler class
PowerMockito.suppress(PowerMockito.method(clazz, "createSslClient"));
Client client = mock(Client.class);
//here we initialize the PaymentHandler.class and finally mock the webServiceClient
Whitebox.setInternalState(clazz, "webServiceClient", client);
PaymentHandler paymentHandler = new PaymentHandler();
WebResource webResource = mock(WebResource.class);
WebResource.Builder builder = mock(WebResource.Builder.class);
when(client.resource(anyString())).thenReturn(webResource);
when(webResource.getRequestBuilder()).thenReturn(builder);
//take note of any(MediaType.class) instead of anyString() from your example. As in
//your PaymentHandler, MediaType is used instead of String
when(builder.type(any(MediaType.class))).thenReturn(builder);
when(builder.accept(any(MediaType.class))).thenReturn(builder);
when(builder.post(Matchers.eq(String.class), anyString())).thenReturn("{}");
paymentHandler.makePayment("payload");
}
}
在我的示例中,我使用了以下依赖项:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.0'
testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.0'
这些是最新版本,但早期版本也可以
下面是我如何模拟它的
@Mock
Client client;
@Mock
WebResource webResource;
@Mock
WebResource.Builder builder;
@Test
public void test() {
ReflectionTestUtils.setField(payeezyHandler,"webServiceClient",client);
Mockito.when(client.resource(anyString())).thenReturn(webResource);
Mockito.when(webResource.getRequestBuilder()).thenReturn(builder);
Mockito.when(builder.type(MediaType.APPLICATION_JSON_TYPE)).thenReturn(builder);
Mockito.when(builder.accept(MediaType.APPLICATION_JSON_TYPE)).thenReturn(builder);
Mockito.when(builder.post(Matchers.eq(String.class),anyString())).thenReturn(fakeResponse());
}
我知道 ReflectionTestUtils 不好用。但是如果你的测试 class 只有一个 public 函数要测试,那么我想没有什么坏处。
这是我的代码
@Service
public class PaymentHandler {
private static final Gson GSON = new Gson();
private static Client webServiceClient = createSslClient(); // function creates a ssl connection
public Response makePayment(String payload) {
WebResource webResource = webServiceClient.resource(url);
WebResource.Builder builder = webResource.getRequestBuilder();
String r = builder
.type(MediaType.APPLICATION_JSON_TYPE)
.accept(MediaType.APPLICATION_JSON_TYPE)
.post(String.class, payload);
Response response = GSON.fromJson(r, Response.class);
}
}
这是我尝试测试它的方法,但它不起作用,它总是调用支付服务。我无法嘲笑它。
Client client = mock(Client.class );
WebResource webResource = mock(WebResource.class);
WebResource.Builder builder = mock(WebResource.Builder.class);
ClientResponse clientResponse = mock(ClientResponse.class);
when(client.resource(anyString())).thenReturn(webResource);
when(webResource.getRequestBuilder()).thenReturn(builder);
when(builder.type(anyString())).thenReturn(builder);
when(builder.accept(anyString())).thenReturn(builder);
when(builder.post(Matchers.eq(String.class), anyString())).thenReturn("Test");
paymentHandler.makePayment(payload); //assume that I send actual payload
有人可以告诉我如何模拟这个吗?
在您的测试中,我没有看到您将 webServiceClient
替换为模拟版本。
但首先,我相信你最好不要在没有依赖注入的情况下编写 PaymentHandler
这样的代码。它可能只是一个简单的组合,将 webServiceClient
注入 PaymentHandler
。没有依赖注入,它不灵活,难以维护,因此不可测试。例如,想象一下,如果初始化这样一个字段需要与外部系统进行一些交互,会发生什么情况。如果没有任何字节码操作库,您将如何测试它?或者您如何轻松地从一个 webServiceClient
迁移到另一个,例如从非 SSL 到 SSL?
尽管存在这些众所周知的问题,但有时我们不得不处理我们无法轻易更改的第 3 方或遗留代码。但是我们想为与 3rd 方代码交互的代码编写测试。出于这个确切的原因,存在一些很酷的测试框架。 PowerMock 就是其中之一,下面是使用它的工作代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest(PaymentHandler.class)
public class PaymentHandlerTest {
@Test
public void test() throws Exception {
//we don't want to initialize the PaymentHandler.class because it might cause some
//heavy undesirable initilization. E.g. if we had referred to PaymentHandler as a class
//literal here, then the webServiceClient would've been initializaed with some "real"
//instance of Client. My PaymentHandler is located in so package. You should specify your
//fully qualified class' name here
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass("so.PaymentHandler");
//now the webServiceClient will be null once we initialize the PaymentHandler class
PowerMockito.suppress(PowerMockito.method(clazz, "createSslClient"));
Client client = mock(Client.class);
//here we initialize the PaymentHandler.class and finally mock the webServiceClient
Whitebox.setInternalState(clazz, "webServiceClient", client);
PaymentHandler paymentHandler = new PaymentHandler();
WebResource webResource = mock(WebResource.class);
WebResource.Builder builder = mock(WebResource.Builder.class);
when(client.resource(anyString())).thenReturn(webResource);
when(webResource.getRequestBuilder()).thenReturn(builder);
//take note of any(MediaType.class) instead of anyString() from your example. As in
//your PaymentHandler, MediaType is used instead of String
when(builder.type(any(MediaType.class))).thenReturn(builder);
when(builder.accept(any(MediaType.class))).thenReturn(builder);
when(builder.post(Matchers.eq(String.class), anyString())).thenReturn("{}");
paymentHandler.makePayment("payload");
}
}
在我的示例中,我使用了以下依赖项:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.0'
testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.0'
这些是最新版本,但早期版本也可以
下面是我如何模拟它的
@Mock
Client client;
@Mock
WebResource webResource;
@Mock
WebResource.Builder builder;
@Test
public void test() {
ReflectionTestUtils.setField(payeezyHandler,"webServiceClient",client);
Mockito.when(client.resource(anyString())).thenReturn(webResource);
Mockito.when(webResource.getRequestBuilder()).thenReturn(builder);
Mockito.when(builder.type(MediaType.APPLICATION_JSON_TYPE)).thenReturn(builder);
Mockito.when(builder.accept(MediaType.APPLICATION_JSON_TYPE)).thenReturn(builder);
Mockito.when(builder.post(Matchers.eq(String.class),anyString())).thenReturn(fakeResponse());
}
我知道 ReflectionTestUtils 不好用。但是如果你的测试 class 只有一个 public 函数要测试,那么我想没有什么坏处。