有点晚了,但我尝试回答这个问题以供将来参考。尽管我同意@Héctor 的评论,但测试 MicroProfile 休息客户端本身(例如,实际测试错误处理程序)或在休息客户端注入的 bean 中可能很有用。
无论如何,您需要一个模拟服务器,例如 WireMock。Quarkus 的官方指南实际上涵盖了这个主题。我可以在这里报告一个例子(我取自这里)。
将此依赖项添加到您的 pom.xml(如果您使用的是 Maven):
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<scope>test</scope>
<version>${wiremock.version}</version>
</dependency>
创建一个类,它将在执行测试之前启动模拟服务器(一旦它们全部执行,它将关闭它):
package org.acme.getting.started.country;
import java.util.Collections;
import java.util.Map;
import com.github.tomakehurst.wiremock.WireMockServer;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
public class WiremockCountries implements QuarkusTestResourceLifecycleManager {
private WireMockServer wireMockServer;
@Override
public Map<String, String> start() {
wireMockServer = new WireMockServer();
wireMockServer.start();
//define a static response when the request matches a url declared as a regex
stubFor(get(urlEqualTo("/v2/name/GR"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
//read the WireMock docs: you can even use a json file in /resources/__files/ (default expected location) in place of a string
.withBody(
"""
[
{
"name": "Ελλάδα",
"capital": "Αθήνα"
}
]
"""
)));
//remap the base url of the external service to the base url of the mock server
return Collections.singletonMap("org.acme.getting.started.country.CountriesService/mp-rest/url", wireMockServer.baseUrl());
}
@Override
public void stop() {
if (null != wireMockServer) {
wireMockServer.stop();
}
}
}
备忘录:目前,您无法测试@Singleton bean,因此请在其余客户端接口上添加注释@ApplicationScoped。
最后,在实际的测试类中使用这个类:
package org.acme.getting.started.country;
import javax.inject.Inject;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@QuarkusTest
@QuarkusTestResource(WiremockCountries.class)
class RegularCountriesServiceTest {
@Inject
@RestClient
CountriesService countriesService;
@Test
void testGR() {
// assertThat(countriesService.getByName("GR")).hasSize(10).extracting("name").contains("Greece");
assertThat(countriesService.getByName("GR")).hasSize(1).extracting("name").contains("Ελλάδα");
}
}
如果您想在上一级测试 REST 客户端,您需要做的就是重用模拟服务器的包装类,并使用 @Inject 注入将 REST 客户端声明为其依赖项的 bean。做这样的事情:
@QuarkusTest
@QuarkusTestResource(WiremockWrapperAsBefore.class)
class MyBusinessClassTest {
@Inject
MyBusinessClass myBusinessClass;
@Test
void testMyRestCleintInjectedIntoMyBusinessClass() {
ResponseDTO dto = myBusinessClass.methodWhichCallsMyMicroProfileRestClient(String someParam);
assertNotNull(dto);
}
}
否则,在其他场景中使用 RestClientBuilder 为 MicroProfile REST 客户端接口创建代理实现可能很有用,如下所示:
import java.net.MalformedURLException;
import java.net.URI;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
public class RestClientTest {
@Test
public void init() throws MalformedURLException {
URI baseURI = URI.create("http://localhost:8080");
PingClient client = RestClientBuilder.newBuilder().
baseUri(baseURI).
build(PingClient.class);
assertNotNull(client);
String result = client.ping();
assertNotNull(result);
}
}
对应的界面很容易猜到,但大致如下:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@Path("/restclient/resources/ping")
@RegisterRestClient
public interface PingClient {
@GET
String ping();
}
在这种情况下,如果您使用 Quarkus,您将不需要以下依赖项,但如果有人使用 MicroProfile 而不是 Quarkus,我会从上面的链接报告无论如何:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-mp-client</artifactId>
<version>3.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>