Search code examples
javaspringgradlecucumber-jvmwiremock

Connection refused when trying to call Wiremock Stub


I'm trying to integrate Cucumber-JVM with WireMock and I keep getting

java.net.ConnectException: Connection refused: connect

I've tried several tutorials, including the Official Docs from cucumber.io And also tried these below:

Introduction to WireMock from Baeldung

Stuff from StackOverflow

Wiremock Github Issues page

My Gradle dependencies:

implementation 'org.springframework.boot:spring-boot-starter-web'   
testImplementation 'io.cucumber:cucumber-java:6.2.2'
testImplementation 'io.cucumber:cucumber-junit:6.2.2'
testImplementation 'io.rest-assured:spring-web-test-client:4.3.1'
testCompile "com.github.tomakehurst:wiremock-jre8:2.27.0"
compile group: 'io.cucumber', name: 'cucumber-spring', version: '6.4.0'

The basic idea is to Mock a Server Response, so in the future I'll be able to create some integration tests between several microservices. The idea came from a book while I'm reading The Cucumber for Java Book If there are better ways to test microservices I'm open to new ideas.

I've a Test Class with my Step Definitions that getting the port info form a propertie file. Like below:

@SpringBootTest
@CucumberContextConfiguration
public class ConnectionWithCucumber {

    @Value("${another.server.port}")
    private int PORT;

    @Rule
    private WireMockRule wireMockRule = new WireMockRule(PORT);

    private String messageResult;

    @Given("I want to read a message")
    public void iWantToRead() {
        createMessageStub();
    }

    @When("I send the request")
    public void iSendTheRequest() {
        messageResult = given().get("localhost:8082/message").getBody().asString();
    }

    @Then("I should be able to read the word {string}")
    public void iShouldBeAbleToReadTheWord(String arg0) {
        assertEquals(arg0, messageResult);
    }

    private void createMessageStub() {
        wireMockRule.stubFor(get(urlEqualTo("/message"))
                .withHeader("Accept", equalTo("application/json"))
                .willReturn(aResponse()
                        .withStatus(200)
                        .withHeader("Content-Type", "application/json")
                        .withBody("message")));
    }
}

And I've also created a repository with a runnable example.

If you don't find a README file, while looking the repo you can run the project by using:

./gradlew cucumber

or if you are on Windows:

gradle cucumber

After I got it working, I refactored the code and left the example on the repository I've linked above, if you are have the same problem check it out.


Solution

  • The WireMockRule depends on the @Rule annotation which comes from JUnit 4. It doesn't have any effect when used in Cucumber. Instead consider using @AutoConfigureWireMock from spring-boot-starter-web to setup wiremock.

    ├── pom.xml
    └── src
        ├── main
        │   └── java
        │       └── com
        │           └── example
        │               └── Application.java
        └── test
            ├── java
            │   └── com
            │       └── example
            │           └── CucumberTest.java
            └── resources
                ├── application.yml
                ├── com
                │   └── example
                │       └── hello.feature
                └── junit-platform.properties
    
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://maven.apache.org/POM/4.0.0"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.1.RELEASE</version>
        </parent>
    
        <groupId>com.example</groupId>
        <artifactId>com.example</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    
        <properties>
            <java.version>11</java.version>
            <cucumber.version>6.5.0</cucumber.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <spring-cloud.version>Hoxton.SR7</spring-cloud.version>
        </properties>
    
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    
        <dependencies>
            <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-starter-contract-stub-runner</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-java</artifactId>
                <version>${cucumber.version}</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-spring</artifactId>
                <version>${cucumber.version}</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-junit-platform-engine</artifactId>
                <version>${cucumber.version}</version>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    </project>
    
    package com.example;
    
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.web.client.RestTemplateBuilder;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @SpringBootApplication
    public class Application {
    
        @Configuration
        @ConfigurationProperties("com.example")
        public static class HelloConfiguration {
    
            String helloService;
    
            public String getHelloService() {
                return helloService;
            }
    
            public void setHelloService(String helloService) {
                this.helloService = helloService;
            }
    
        }
    
        @RestController
        public static class HelloController {
    
            private final RestTemplate helloService;
    
            public HelloController(
                    RestTemplateBuilder restTemplateBuilder,
                    HelloConfiguration configuration) {
                this.helloService = restTemplateBuilder
                        .rootUri(configuration.getHelloService())
                        .build();
            }
    
            @RequestMapping("/local")
            public String local() {
                return "Greetings from Local!";
            }
    
            @RequestMapping("/remote")
            public String remote() {
                return helloService.getForObject("/", String.class);
            }
    
        }
    
    }
    
    package com.example;
    
    import com.github.tomakehurst.wiremock.client.WireMock;
    import io.cucumber.java.en.Given;
    import io.cucumber.junit.platform.engine.Cucumber;
    import io.cucumber.spring.CucumberContextConfiguration;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
    import org.springframework.test.web.servlet.MockMvc;
    
    import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
    import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
    import static org.hamcrest.CoreMatchers.equalTo;
    import static org.springframework.http.MediaType.APPLICATION_JSON;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    
    @Cucumber
    @CucumberContextConfiguration
    @SpringBootTest
    @AutoConfigureMockMvc
    @AutoConfigureWireMock(port = 0)
    public class CucumberTest {
    
        @Autowired
        private MockMvc mvc;
    
        @Given("the application says hello")
        public void getLocalHello() throws Exception {
            mvc.perform(get("/local").accept(APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(content().string(equalTo("Greetings from Local!")));
        }
    
        @Given("the stub says hello")
        public void getRemoteHello() throws Exception {
            stubFor(WireMock.get("/").willReturn(okJson("Greetings from Stub!")));
    
            mvc.perform(get("/remote").accept(APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(content().string(equalTo("Greetings from Stub!")));
        }
    
    }
    
    Feature: Hello world
    
      Scenario: Calling a rest end point
        * the application says hello
        * the stub says hello
    
    com:
      example:
        hello-service: http://localhost:${wiremock.server.port}