英文:
Mock API calls During Unit Test cases Spring boot
问题
我有两个微服务,微服务A(上下文路径 - /abc)和微服务B(上下文路径 - /def)。
示例URL:test.domain.com/abc/endpoint1,test.domain.com/def/endpoint2
在微服务A的一个API中(test.domain.com/abc/endpoint1),它内部调用了微服务B(/def/endpoint2)->这个内部调用的前缀生成如下
(从请求中提取域名,然后附加/def/endpoint2以进行REST调用,总URL将变为(test.domain.com/def/endpoint2)
问题:当我们从控制器级别开始编写单元测试用例时,我们使用TestRestTemplate
为了进行测试,我们需要使用http://localhost:portnumber/abc/endpoint1进行测试..
现在,def服务的URL也将派生为http://localhost:portnumber/def/endpoint2
如何模拟这个响应(注意:我们不能在相同的端口上使用模拟服务器,否则会出现端口绑定异常)。是否有任何解决方法?
是否有办法在使用TestRestTemplate时设置类似网关的配置,以将http://localhost:portnumber/def/*调用路由到模拟服务器以获取响应,并将http://localhost:portnumber/abc/*用于实际测试的API服务?
英文:
I have two microservices Microservice A ( context path - /abc ) and microservice B (context path - /def )
Example URLs: test.domain.com/abc/endpoint1 ,test.domain.com/def/endpoint2
In one of the apis of Microservice A ( test.domain.com/abc/endpoint1) internally its making call to Microservice B (/def/endpoint2) -> the prefix for this internal call is generated as follows
(Extract the domain from the request and then append /def/endpoint2 to make a rest call the total url will become as (test.domain.com/def/endpoint2)
Problem : When we are writting unit test cases starting controller level we are using TestRestTemplate
For this testing we need to use http://localhost:portnumber/abc/endpoint1 to test ..
Now the url of the def service also will be derived as http://localhost:portnumber/def/endpoint2
How to mock this response ( Note: We cannot use mock server on same port, we will get port binding exception) . Is there any workaround for the same?
Is there any way to have gateway kind of setup while using TestRestTemplate to route http://localhost:portnumber/def/* calls to get response from mockserver and http://localhost:portnumber/abc/* to make the actual API Service under test?
答案1
得分: 1
你可以使用ClientHttpRequestInterceptor
来实现这个功能,并且可以操作实际的URI
,以便在匹配第二个微服务的路径时调用它。这可能是一个天真的原型实现:
public class UrlRewriter implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
try {
if (httpRequest.getURI().toString().contains("/def/abc")) {
HttpRequest modifiedRequest = new MockClientHttpRequest(HttpMethod.GET, new URI("http://localhost:8888/def/abc"));
return clientHttpRequestExecution.execute(modifiedRequest, bytes);
} else {
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
}
}
}
然后,你可以为你的测试提供一个RestTemplateBuilder
类型的自定义bean,该bean将被TestRestTemplate
使用:
@SpringBootTest(webEnvironment = RANDOM_PORT)
public class TestOne {
@TestConfiguration
static class TestConfig {
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().interceptors(new UrlRewriter());
}
}
@Autowired
private TestRestTemplate testRestTemplate;
@Test
public void test() {
assertNotNull(testRestTemplate);
testRestTemplate.getForObject("/abc/endpoint1", String.class);
}
}
英文:
You could use a ClientHttpRequestInterceptor
for this and manipulate the actual URI
to call if it matches the path of your second microservice.
This might be a naive protoypish implementation:
public class UrlRewriter implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
try {
if (httpRequest.getURI().toString().contains("/def/abc")) {
HttpRequest modifiedRequest = new MockClientHttpRequest(HttpMethod.GET, new URI("http://localhost:8888/def/abc"));
return clientHttpRequestExecution.execute(modifiedRequest, bytes);
} else {
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
}
}
}
And then you can provide a custom bean of type RestTemplateBuilder
for your test that is picked up by the TestRestTemplate
:
@SpringBootTest(webEnvironment = RANDOM_PORT)
public class TestOne {
@TestConfiguration
static class TestConfig {
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().interceptors(new UrlRewriter());
}
}
@Autowired
private TestRestTemplate testRestTemplate;
@Test
public void test() {
assertNotNull(testRestTemplate);
testRestTemplate.getForObject("/abc/endpoint1", String.class);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论