Back to Repositories

Testing Gateway Predicate Routing and Circuit Breaking in SpringCloudLearning

This test suite validates Spring Cloud Gateway predicates and circuit breaker functionality using WireMock for HTTP request simulation. It demonstrates essential gateway routing behaviors and fallback mechanisms in a Spring Cloud microservices environment.

Test Coverage Overview

The test suite covers two critical gateway functionalities:
  • HTTP GET request routing and response header validation
  • Timeout handling with circuit breaker fallback scenarios
  • Integration with WireMock for HTTP request simulation
  • Response body and status verification

Implementation Analysis

The testing approach utilizes Spring’s WebTestClient for reactive endpoint testing, combined with WireMock for external service simulation. The implementation leverages Spring Boot’s test framework features, including random port assignment and automated WireMock configuration.

Key patterns include request stubbing, response body validation, and circuit breaker testing with configurable delays.

Technical Details

  • SpringRunner for test execution
  • WebTestClient for reactive HTTP testing
  • WireMock for HTTP request simulation
  • Spring Boot Test for environment configuration
  • AssertJ for response validation
  • Circuit breaker configuration for timeout handling

Best Practices Demonstrated

The test suite exemplifies several testing best practices including isolated test environments, proper stub configuration, and comprehensive assertion coverage. Notable practices include:
  • Automated test infrastructure setup
  • Explicit request/response contract testing
  • Timeout and fallback behavior verification
  • Clean separation of test configuration and execution

forezp/springcloudlearning

sc-f-gateway-predicate/src/test/java/gateway/ApplicationTest.java

            
//package gateway;
//
//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.test.context.junit4.SpringRunner;
//import org.springframework.test.web.reactive.server.WebTestClient;
//
//import static com.github.tomakehurst.wiremock.client.WireMock.*;
//import static org.assertj.core.api.Assertions.*;
//
///**
// * @author Ryan Baxter
// */
//// tag::code[]
//@RunWith(SpringRunner.class)
//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
//		properties = {"httpbin=http://localhost:${wiremock.server.port}"})
//@AutoConfigureWireMock(port = 0)
//public class ApplicationTest {
//
//	@Autowired
//	private WebTestClient webClient;
//
//	@Test
//	public void contextLoads() throws Exception {
//		//Stubs
//		stubFor(get(urlEqualTo("/get"))
//				.willReturn(aResponse()
//					.withBody("{\"headers\":{\"Hello\":\"World\"}}")
//					.withHeader("Content-Type", "application/json")));
//		stubFor(get(urlEqualTo("/delay/3"))
//			.willReturn(aResponse()
//				.withBody("no fallback")
//				.withFixedDelay(3000)));
//
//		webClient
//			.get().uri("/get")
//			.exchange()
//			.expectStatus().isOk()
//			.expectBody()
//			.jsonPath("$.headers.Hello").isEqualTo("World");
//
//		webClient
//			.get().uri("/delay/3")
//			.header("Host", "www.hystrix.com")
//			.exchange()
//			.expectStatus().isOk()
//			.expectBody()
//			.consumeWith(
//				response -> assertThat(response.getResponseBody()).isEqualTo("fallback".getBytes()));
//	}
//}
//// end::code[]