I use Spring-Cloud-Netflix for communication between micro services. Let's say I have two services, Foo and Bar, and Foo consumes one of Bar's REST endpoints. I use an interface annotated with @FeignClient
:
@FeignClient
public interface BarClient {
@RequestMapping(value = "/some/url", method = "POST")
void bazzle(@RequestBody BazzleRequest);
}
Then I have a service class SomeService
in Foo, which calls the BarClient
.
@Component
public class SomeService {
@Autowired
BarClient barClient;
public String doSomething() {
try {
barClient.bazzle(new BazzleRequest(...));
return "so bazzle my eyes dazzle";
} catch(FeignException e) {
return "Not bazzle today!";
}
}
}
Now, to make sure the communication between services works, I want to build a test that fires a real HTTP request against a fake Bar server, using something like WireMock. The test should make sure that feign correctly decodes the service response and reports it to SomeService
.
public class SomeServiceIntegrationTest {
@Autowired SomeService someService;
@Test
public void shouldSucceed() {
stubFor(get(urlEqualTo("/some/url"))
.willReturn(aResponse()
.withStatus(204);
String result = someService.doSomething();
assertThat(result, is("so bazzle my eyes dazzle"));
}
@Test
public void shouldFail() {
stubFor(get(urlEqualTo("/some/url"))
.willReturn(aResponse()
.withStatus(404);
String result = someService.doSomething();
assertThat(result, is("Not bazzle today!"));
}
}
How can I inject such a WireMock server into eureka, so that feign is able to find it and communicate with it? What kind of annotation magic do I need?
Probably there is no way to make WireMock comunicate directly with Eureka Server, but you can use other variants to configure test environment that you need.
BarClient
endpoint logic, and integration test is only about realhttp
transport layer, then you can use Mockito forBarClient
endpoint stub.I suppose that in order to implement 1 and 2 using Spring-Boot, you will need to make two separate applications for a test environment. One for Eureka Service Registry under Jetty and another for
BarClient
endpoint stub under Jetty too.Another solution is to manually configure Jetty and Eureka in test application context. I think that this is a better way but in such case you must to understand what
@EnableEurekaServer
and@EnableDiscoveryClient
annotations do with Spring application context.Use Spring's RestTemplate instead of feign. RestTemplate is also able to resolve service names via eureka, so you can do something like this:
This is way easier testable with Wiremock than feign.
Here is an example how to do the wiring of Feign and WireMock with random port (based on Spring-Boot github answer).
Alternatively you can try playing with
System.setProperty()
in@BeforeClass
method of your test.There used to be basically two options for doing integration tests for microservices applications:
First option has the obvious disadvantage of the hassle of deploying all the dependencies (other services, databases, etc) as well. In addition, it is slow and hard to debug.
Second option is faster and has less hassle but it is easy to end up with stubs that behave differently than the reality in time, due to possible code changes. So it is possible to have successful tests but failing app when deployed to prod.
A better solution would be using consumer driven contract verification, so that you will make sure that provider service's API is compliant with the consumer calls. For this purpose, Spring developers can use Spring Cloud Contract. For other environments, there is a framework called PACT. Both can be used with Feign clients as well. Here is an example with PACT.
Here is an example of using WireMock to test SpringBoot configuration with Feign client and Hystrix fallback.
If you are using Eureka as a server discovery, you need to disable it by setting a property
"eureka.client.enabled=false"
.First, we need to enable the Feign/Hystrix configuration for our application:
Please note that we are specifying a fallback class for the Feign client. Fallback class will be called every time Feign client call fails (e.g. connection timeout).
In order for tests to work, we need to configure the Ribbon loadbalancer (will be used internally by Feign client when sending http request):
Ribbon server list need to match the url (host and port) of our WireMock configuration.
I personally prefer mockServer to stub any restful API, it is easy to use and is similar to wiremock, but is very powerful compared to the latter.
I have attached the sample code written with groovy/spock for stubbing a GET restful call with mockServer.
First autowire the mockServer instance in test class
start the mockServer instance from the setupSpec() method, this method is similar to junit method annotated with @BeforeClass.
define the required stub in the corresponding unit test
after the execution of test cases, stop the mock server