spring-cloud / spring-cloud-contract

Support for Consumer Driven Contracts in Spring
https://cloud.spring.io/spring-cloud-contract
Apache License 2.0
718 stars 438 forks source link

fromRequest doesn't get resolved to a value #1238

Closed ciberkleid closed 4 years ago

ciberkleid commented 5 years ago

Bug report

My BaseClass:

public class BaseClass {
    @Before
    public void setup() {
        HelloService service = BDDMockito.mock(HelloService.class);
        BDDMockito.given(service.sayHello(anyString())).willAnswer(invocation -> "Hello " + invocation.getArgument(0) + "!");
        RestAssuredMockMvc.standaloneSetup(new HelloServiceController(service));
    }

}

My contract:

Contract.make {
    description("""
should return a hello and name
""")
    request {
        method GET()
        urlPath("/" + anyNonBlankString())
    }
    response {
        status 200
        body (
                "Hello " + fromRequest().path(0) + "!"
        )
    }
}

Results in a compilation failure: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile (default-testCompile) on project s1p-hello-service: Compilation failure: Compilation failure: [ERROR] /Users/ciberkleid/workspace/s1p-2019/s1p-hello-service/target/generated-test-sources/contracts/spring/k8s/helloservice/contracttests/S1p_hello_clientTest.java:[29,141] illegal escape character [ERROR] /Users/ciberkleid/workspace/s1p-2019/s1p-hello-service/target/generated-test-sources/contracts/spring/k8s/helloservice/contracttests/S1p_hello_clientTest.java:[29,144] illegal escape character [ERROR] /Users/ciberkleid/workspace/s1p-2019/s1p-hello-service/target/generated-test-sources/contracts/spring/k8s/helloservice/contracttests/S1p_hello_clientTest.java:[29,147] illegal escape character [ ...

And generated test is:
    @Test
    public void validate_shouldReturnHelloName() throws Exception {
        // given:
            MockMvcRequestSpecification request = given();

        // when:
            ResponseOptions response = given().spec(request)
                    .get("/org.springframework.cloud.contract.spec.internal.ClientDslProperty(DslProperty(clientValue:^\s*\S[\S\s]*, serverValue:JBQAGPGNJYEOGPEZBMUL))");

        // then:
            assertThat(response.statusCode()).isEqualTo(200);
        // and:
            String responseBody = response.getBody().asString();
            assertThat(responseBody).isEqualTo("Hello DslProperty(clientValue:org.springframework.cloud.contract.spec.internal.ClientDslProperty(DslProperty(clientValue:^\s*\S[\S\s]*, serverValue:JBQAGPGNJYEOGPEZBMUL)), serverValue:org.springframework.cloud.contract.spec.internal.ClientDslProperty(DslProperty(clientValue:^\s*\S[\S\s]*, serverValue:JBQAGPGNJYEOGPEZBMUL)))!");
    }

Another example, using same base class:

Contract is:

Contract.make {
    description("""
should return a hello and name
""")
    request {
        method GET()
//        url "/Rockstar"
        url anyNonBlankString()
    }
    response {
        status 200
        body (
                "Hello " + fromRequest().url() + "!"
        )
    }
}

Error is: [ERROR] Failures: [ERROR] S1p_hello_clientTest.validate_shouldReturnHelloName:35 expected:<"Hello [DslProperty(clientValue:KKLXPCSMDSVMOFIQQMLO, serverValue:KKLXPCSMDSVMOFIQQMLO)]!"> but was:<"Hello [KKLXPCSMDSVMOFIQQMLO]!"> [INFO] [ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0

Generated test is:

    @Test
    public void validate_shouldReturnHelloName() throws Exception {
        // given:
            MockMvcRequestSpecification request = given();

        // when:
            ResponseOptions response = given().spec(request)
                    .get("KKLXPCSMDSVMOFIQQMLO");

        // then:
            assertThat(response.statusCode()).isEqualTo(200);
        // and:
            String responseBody = response.getBody().asString();
            assertThat(responseBody).isEqualTo("Hello DslProperty(clientValue:KKLXPCSMDSVMOFIQQMLO, serverValue:KKLXPCSMDSVMOFIQQMLO)!");
    }
marcingrzejszczak commented 4 years ago

Ok there are a couple of issues here.

You can't do this urlPath("/" + anyNonBlankString()). You can either do urlPath( anyNonBlankString()) or a GString urlPath("/${nonBlank()})

The same with fromRequest instead of "Hello " + fromRequest().path(0) + "!" do "Hello ${fromRequest().path(0)} !"

In other words you contract should look like this

Contract contractDsl = Contract.make {
                request {
                    method GET()
                    urlPath(anyNonBlankString())
                }
                response {
                    status 200
                    body (
                            "Hello ${fromRequest().path(0)}!"
                    )
                }
            }