Cloud Contract

We will create 2 applications:

Service Producer Application

Create Initial Code Base

  • Go to https://start.spring.io/

  • Add the following dependencies:

    • lombok

    • spring-boot-starter-test

    • spring-cloud-starter-contract-verifier

  • Click Generate

Dependencies

Dependencies used in pom.xml:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-verifier</artifactId>
    <scope>test</scope>
</dependency>

Properties

Add the following properties into src/main/resources/application.properties:

server.port=9090

Service

Create a new file src/main/java/com/example/DefaultService.java:

@Service
public class DefaultService {

    public String isEven(Integer number) {
        return number % 2 == 0 ? "Even" : "Odd";
    }
}

Controller

Create a new file src/main/java/com/example/DefaultController.java:

@RestController
public class DefaultController {

    @Autowired
    private DefaultService defaultService;

    /**
     * http://localhost:9090/validate/even-number?number=NUMBER_HERE
     * @param number
     * @return
     */
    @GetMapping("/validate/even-number")
    public String isNumberEven(@RequestParam("number") Integer number) {
        return defaultService.isEven(number);
    }
}

Create Test

Create a new file src/test/java/com/example/spring_cloud_contract/producer/BaseClass.java:

@SpringBootTest(classes = SpringCloudContractApplication.class)
public abstract class BaseClass {

    @Autowired
    DefaultController defaultController;

//    @MockitoBean
//    DefaultService defaultService;

    @BeforeEach
    public void setup() {
        RestAssuredMockMvc.standaloneSetup(defaultController);
//        Mockito.when(defaultService.isEven(2))
//                .thenReturn("Even");
    }

}

Contract

Create a new file src/test/resources/contracts/shouldReturnEvenWhenRequestParamIsEven.groovy:

package contracts

import org.springframework.cloud.contract.spec.Contract

Contract.make {
    description "should return even when number input is even"
    request{
        method GET()
        url("/validate/even-number") {
            queryParameters {
                parameter("number", "2")
            }
        }
    }
    response {
        body("Even")
        status 200
    }
}

Run Test

mvn clean install

This will auto-generate a test based on the contract and run it at the same time.sh

Service Consumer Application

Create Initial Code Base

  • Go to https://start.spring.io/

  • Add the following dependencies:

    • spring-boot-starter-web

    • spring-boot-starter-test

    • spring-cloud-contract-wiremock

    • spring-cloud-contract-stub-runner

  • Click Generate

Dependencies

Dependencies used in pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-wiremock</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-stub-runner</artifactId>
    <scope>test</scope>
</dependency>

Controller

Create a new file src/main/java/com/example/DefaultController.java:

@RestController
class DefaultController {

    private final RestTemplate restTemplate;

    DefaultController(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    @GetMapping("/calculate")
    public String checkOddAndEven(@RequestParam("number") Integer number) {
        return restTemplate.getForObject("http://localhost:9090/validate/prime-number?number=" + number, String.class);
    }
}

Create Test

Create a new file src/test/java/com/example/spring_cloud_contract/consumer/SpringCloudContractApplicationTests.java:

@SpringBootTest
@AutoConfigureStubRunner(
            ids = "com.example:spring-cloud-contract-producer:0.0.1-SNAPSHOT:stubs:9090",
            stubsMode = StubRunnerProperties.StubsMode.LOCAL
)
class SpringCloudContractApplicationTests {

    @Test
    void get_person_from_service_contract() {
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:9090/validate/even-number?number=2", String.class);

            BDDAssertions.then(responseEntity.getStatusCode().is2xxSuccessful()).isEqualTo(true);
            BDDAssertions.then(responseEntity.getBody()).isEqualTo("Even");
    }
}

Run Test

mvn clean package