diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml index c5ebb4116a..a2c4b3509f 100644 --- a/spring-cloud/pom.xml +++ b/spring-cloud/pom.xml @@ -46,7 +46,7 @@ spring-cloud-circuit-breaker spring-cloud-eureka-self-preservation - + spring-cloud-netflix-feign spring-cloud-sentinel spring-cloud-dapr spring-cloud-docker diff --git a/spring-cloud/spring-cloud-netflix-feign/pom.xml b/spring-cloud/spring-cloud-netflix-feign/pom.xml index 8ff09d3070..f519b6316b 100644 --- a/spring-cloud/spring-cloud-netflix-feign/pom.xml +++ b/spring-cloud/spring-cloud-netflix-feign/pom.xml @@ -51,13 +51,16 @@ spring-boot-starter-test test + + org.springframework.cloud + spring-cloud-contract-wiremock + test + Camden.SR7 8.18.0 - - \ No newline at end of file diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java index 80a455a4c4..454caab38c 100644 --- a/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java +++ b/spring-cloud/spring-cloud-netflix-feign/src/main/java/com/baeldung/cloud/netflix/feign/client/JSONPlaceHolderClient.java @@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMethod; import java.util.List; @FeignClient(value = "jplaceholder", - url = "https://jsonplaceholder.typicode.com/", + url = "${external.api.url}", configuration = ClientConfiguration.class, fallback = JSONPlaceHolderFallback.class) public interface JSONPlaceHolderClient { @@ -19,7 +19,7 @@ public interface JSONPlaceHolderClient { @RequestMapping(method = RequestMethod.GET, value = "/posts") List getPosts(); - @RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json") Post getPostById(@PathVariable("postId") Long postId); + } diff --git a/spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties b/spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties index 5927ccb9c1..a8a29dcdd5 100644 --- a/spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties +++ b/spring-cloud/spring-cloud-netflix-feign/src/main/resources/application.properties @@ -1,3 +1,5 @@ spring.application.name=netflix-feign logging.level.com.baeldung.cloud.netflix.feign.client=DEBUG feign.hystrix.enabled=true + +external.api.url=https://jsonplaceholder.typicode.com/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/ExampleTestApplication.java b/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/ExampleTestApplication.java deleted file mode 100644 index f3c8459f87..0000000000 --- a/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/ExampleTestApplication.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.baeldung.cloud.netflix.feign; - -import com.baeldung.cloud.netflix.feign.config.ClientConfiguration; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -@EnableAutoConfiguration -@ContextConfiguration(classes = { ClientConfiguration.class }) -public class ExampleTestApplication { - - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - } -} diff --git a/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java b/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java index 880948d6d1..9ee925201d 100644 --- a/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java +++ b/spring-cloud/spring-cloud-netflix-feign/src/test/java/com/baeldung/cloud/netflix/feign/NetflixFeignUnitTest.java @@ -2,42 +2,97 @@ package com.baeldung.cloud.netflix.feign; import com.baeldung.cloud.netflix.feign.model.Post; import com.baeldung.cloud.netflix.feign.service.JSONPlaceHolderService; +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; -import static org.junit.Assert.assertFalse; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.exactly; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(properties = {"external.api.url=http://localhost:${wiremock.server.port}"}) +@AutoConfigureWireMock(port = 0) public class NetflixFeignUnitTest { @Autowired private JSONPlaceHolderService jsonPlaceHolderService; - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { + @Before + public void setup() { + WireMock.reset(); } @Test - public void whenGetPosts_thenListPostSizeGreaterThanZero() { + public void givenExternalApiAvailable_whenGetPosts_thenPostsReturned() { + + WireMock.stubFor(get(urlEqualTo("/posts")) + .willReturn(okJson("[{ \"userId\": 1, \"id\": 1, \"title\": \"post 1 title\", \"body\": \"post 1 body\" }, " + + "{ \"userId\": 1, \"id\": 2, \"title\": \"post 2 title\", \"body\": \"post 2 body\" }]"))); List posts = jsonPlaceHolderService.getPosts(); - assertFalse(posts.isEmpty()); + assertEquals(2, posts.size()); + verify(exactly(1), getRequestedFor(urlEqualTo("/posts"))); } @Test - public void whenGetPostWithId_thenPostExist() { + public void givenExternalApiUnavailable_whenGetPosts_thenEmpty() { + + WireMock.stubFor(get(urlEqualTo("/posts")) + .willReturn(aResponse().withStatus(500))); + + List posts = jsonPlaceHolderService.getPosts(); + + assertTrue(posts.isEmpty()); + verify(exactly(1), getRequestedFor(urlEqualTo("/posts"))); + } + + @Test + public void givenExternalApiAvailable_whenGetPostWithId_thenPostExists() { + + WireMock.stubFor(get(urlEqualTo("/posts/1")) + .willReturn(okJson("{ \"userId\": 1, \"id\": 1, \"title\": \"post 1 title\", \"body\": \"post 1 body\" }"))); Post post = jsonPlaceHolderService.getPostById(1L); assertNotNull(post); + verify(exactly(1), getRequestedFor(urlEqualTo("/posts/1"))); } + @Test + public void givenExternalApiUnavailable_whenGetPostWithId_thenNull() { + + WireMock.stubFor(get(urlEqualTo("/posts/1")) + .willReturn(aResponse().withStatus(500))); + + Post post = jsonPlaceHolderService.getPostById(1L); + + assertNull(post); + verify(exactly(1), getRequestedFor(urlEqualTo("/posts/1"))); + } + + private static ResponseDefinitionBuilder okJson(String json) { + return aResponse() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody(json); + } }