diff --git a/checkstyle-cachefile b/checkstyle-cachefile index f08d7696c5..fa1861ea21 100644 --- a/checkstyle-cachefile +++ b/checkstyle-cachefile @@ -1,2 +1,2 @@ -#Tue Aug 29 08:23:21 UTC 2017 +#Tue Aug 29 08:38:20 UTC 2017 configuration*?=7DF68C2DFDA78CDA9DA5D6C9D1024FEEE69AE1D5 diff --git a/multi/_spring_cloud_contract_verifier.html b/multi/_spring_cloud_contract_verifier.html index 33816e8c1a..2b20581c6b 100644 --- a/multi/_spring_cloud_contract_verifier.html +++ b/multi/_spring_cloud_contract_verifier.html @@ -372,7 +372,9 @@ git merge --no-ff contract-change-pr git push origin master

Then we assume that your CI would run sth like ./mvnw clean deploy which would publish both the application and the stub artifcats.

Consumer side (Loan Issuance) final step

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):

merge branch to master

git checkout master
 git merge --no-ff contract-change-pr

work online

Now you can disable the offline work for Spring Cloud Contract Stub Runner and provide where the repository with your stubs is placed. At this moment the stubs of the server side will be automatically downloaded from Nexus / Artifactory. You can switch off the value of the workOffline parameter in your annotation. Below you can see an -example of achieving the same by changing the properties.

link:https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml[]

And that’s it!

2.1.5 Dependencies

The best way to add the dependencies is to just use the proper starter dependency.

For stub-runner use spring-cloud-starter-stub-runner and when you’re using a plugin just add +example of achieving the same by changing the properties.

stubrunner:
+  ids: 'com.example:http-server-dsl:+:stubs:8080'
+  repositoryRoot: http://repo.spring.io/libs-snapshot

And that’s it!

2.1.5 Dependencies

The best way to add the dependencies is to just use the proper starter dependency.

For stub-runner use spring-cloud-starter-stub-runner and when you’re using a plugin just add spring-cloud-starter-contract-verifier.

2.1.6 Additional links

Below you can find some resources related to Spring Cloud Contract Verifier and Stub Runner. Note that some can be outdated since the Spring Cloud Contract Verifier project is under constant development.

Spring Cloud Contract video

You can check out the video from the Warsaw JUG about Spring Cloud Contract:

Readings

2.1.7 Samples

Here you can find some samples.

2.2 FAQ

2.2.1 Why use Spring Cloud Contract Verifier and not X ?

For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you’re already creating software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make @@ -1406,13 +1408,71 @@ automatically for you.

}

2.5.2 Publishing stubs as JARs

The easiest approach would be to centralize the way stubs are kept. For example you can keep them as JARs in a Maven repository.

[Tip]Tip

For both Maven and Gradle the setup comes out of the box. But you can customize it if you want to.

Maven. 

<!-- First disable the default jar setup in the properties section-->
-link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer_with_restdocs/pom.xml[]
+<!-- we don't want the verifier to do a jar for us -->
+<spring.cloud.contract.verifier.skip>true</spring.cloud.contract.verifier.skip>
 
 <!-- Next add the assembly plugin to your build -->
-link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer_with_restdocs/pom.xml[]
+<!-- we want the assembly plugin to generate the JAR -->
+<plugin>
+	<groupId>org.apache.maven.plugins</groupId>
+	<artifactId>maven-assembly-plugin</artifactId>
+	<executions>
+		<execution>
+			<id>stub</id>
+			<phase>prepare-package</phase>
+			<goals>
+				<goal>single</goal>
+			</goals>
+			<inherited>false</inherited>
+			<configuration>
+				<attach>true</attach>
+				<descriptor>${basedir}/src/assembly/stub.xml</descriptor>
+			</configuration>
+		</execution>
+	</executions>
+</plugin>
 
 <!-- Finally setup your assembly. Below you can find the contents of src/main/assembly/stub.xml -->
-link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer_with_restdocs/src/assembly/stub.xml[]

+<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> + <id>stubs</id> + <formats> + <format>jar</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + <fileSets> + <fileSet> + <directory>src/main/java</directory> + <outputDirectory>/</outputDirectory> + <includes> + <include>**com/example/model/*.*</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.build.directory}/classes</directory> + <outputDirectory>/</outputDirectory> + <includes> + <include>**com/example/model/*.*</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.build.directory}/snippets/stubs</directory> + <outputDirectory>META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings</outputDirectory> + <includes> + <include>**/*</include> + </includes> + </fileSet> + <fileSet> + <directory>${basedir}/src/test/resources/contracts</directory> + <outputDirectory>META-INF/${project.groupId}/${project.artifactId}/${project.version}/contracts</outputDirectory> + <includes> + <include>**/*.groovy</include> + </includes> + </fileSet> + </fileSets> +</assembly>

Gradle. 

ext {
 	contractsDir = file("mappings")
@@ -3425,18 +3485,217 @@ got the name of the contract file WithList.groovy p
 contract had index 1 in the list of contracts in the file).

[Tip]Tip

As you can see it’s much better if you name your contracts since then your tests are far more meaningful.

2.18 Customization

2.18.1 Extending the DSL

It is possible to provide your own functions to the DSL. The key requirement for this feature was to maintain the static compatibility. Below you will be able to see an example -of:

  • creation of a JAR with reusable classes
  • referencing of these classes in the DSLs

The full example can be found here.

Common JAR

Below you can find three classes that we will reuse in the DSLs.

PatternUtils contains functions used by both the consumer and the producer.

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/common/src/main/java/com/example/PatternUtils.java[]

ConsumerUtils contains functions used by the consumer.

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/common/src/main/java/com/example/ConsumerUtils.java[]

ProducerUtils contains functions used by the producer.

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/common/src/main/java/com/example/ProducerUtils.java[]

Adding the dependency to project

In order for the plugins and IDE to be able to reference the common JAR classes you need +of:

  • creation of a JAR with reusable classes
  • referencing of these classes in the DSLs

The full example can be found here.

Common JAR

Below you can find three classes that we will reuse in the DSLs.

PatternUtils contains functions used by both the consumer and the producer.

package com.example;
+
+import java.util.regex.Pattern;
+
+/**
+ * If you want to use {@link Pattern} directly in your tests
+ * then you can create a class resembling this one. It can
+ * contain all the {@link Pattern} you want to use in the DSL.
+ *
+ * <pre>
+ * {@code
+ * request {
+ *     body(
+ *         [ age: $(c(PatternUtils.oldEnough()))]
+ *     )
+ * }
+ * </pre>
+ *
+ * Notice that we're using both {@code $()} for dynamic values
+ * and {@code c()} for the consumer side.
+ *
+ * @author Marcin Grzejszczak
+ */
+//tag::impl[]
+public class PatternUtils {
+
+	public static String tooYoung() {
+		//remove::start[]
+		return "[0-1][0-9]";
+		//remove::end[return]
+	}
+
+	public static Pattern oldEnough() {
+		//remove::start[]
+		return Pattern.compile("[2-9][0-9]");
+		//remove::end[return]
+	}
+
+	/**
+	 * Makes little sense but it's just an example ;)
+	 */
+	public static Pattern ok() {
+		//remove::start[]
+		return Pattern.compile("OK");
+		//remove::end[return]
+	}
+}
+//end::impl[]

ConsumerUtils contains functions used by the consumer.

package com.example;
+
+import org.springframework.cloud.contract.spec.internal.ClientDslProperty;
+
+/**
+ * DSL Properties passed to the DSL from the consumer's perspective.
+ * That means that on the input side {@code Request} for HTTP
+ * or {@code Input} for messaging you can have a regular expression.
+ * On the {@code Response} for HTTP or {@code Output} for messaging
+ * you have to have a concrete value.
+ *
+ * @author Marcin Grzejszczak
+ */
+//tag::impl[]
+public class ConsumerUtils {
+	/**
+	 * Consumer side property. By using the {@link ClientDslProperty}
+	 * you can omit most of boilerplate code from the perspective
+	 * of dynamic values. Example
+	 *
+	 * <pre>
+	 * {@code
+	 * request {
+	 *     body(
+	 *         [ age: $(ConsumerUtils.oldEnough())]
+	 *     )
+	 * }
+	 * </pre>
+	 *
+	 * That way it's in the implementation that we decide what value we will pass to the consumer
+	 * and which one to the producer.
+	 *
+	 * @author Marcin Grzejszczak
+	 */
+	public static ClientDslProperty oldEnough() {
+		//remove::start[]
+		// this example is not the best one and
+		// theoretically you could just pass the regex instead of `ServerDslProperty` but
+		// it's just to show some new tricks :)
+		return new ClientDslProperty(PatternUtils.oldEnough(), 40);
+		//remove::end[return]
+	}
+
+}
+//end::impl[]

ProducerUtils contains functions used by the producer.

package com.example;
+
+import org.springframework.cloud.contract.spec.internal.ServerDslProperty;
+
+/**
+ * DSL Properties passed to the DSL from the producer's perspective.
+ * That means that on the input side {@code Request} for HTTP
+ * or {@code Input} for messaging you have to have a concrete value.
+ * On the {@code Response} for HTTP or {@code Output} for messaging
+ * you can have a regular expression.
+ *
+ * @author Marcin Grzejszczak
+ */
+//tag::impl[]
+public class ProducerUtils {
+
+	/**
+	 * Producer side property. By using the {@link ProducerUtils}
+	 * you can omit most of boilerplate code from the perspective
+	 * of dynamic values. Example
+	 *
+	 * <pre>
+	 * {@code
+	 * response {
+	 *     body(
+	 *         [ status: $(ProducerUtils.ok())]
+	 *     )
+	 * }
+	 * </pre>
+	 *
+	 * That way it's in the implementation that we decide what value we will pass to the consumer
+	 * and which one to the producer.
+	 */
+	public static ServerDslProperty ok() {
+		// this example is not the best one and
+		// theoretically you could just pass the regex instead of `ServerDslProperty` but
+		// it's just to show some new tricks :)
+		return new ServerDslProperty( PatternUtils.ok(), "OK");
+	}
+}
+//end::impl[]

Adding the dependency to project

In order for the plugins and IDE to be able to reference the common JAR classes you need to pass the dependency to your project.

Test dependency in project’s dependencies

First add the common jar dependency as a test dependency. That way since your contracts files are available at test resources path, automatically the common jar classes will be visible in your Groovy files.

Maven.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/pom.xml[]

+

<dependency>
+	<groupId>com.example</groupId>
+	<artifactId>beer-common</artifactId>
+	<version>${project.version}</version>
+	<scope>test</scope>
+</dependency>

Gradle.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/build.gradle[]

+

testCompile("com.example:beer-common:0.0.1-SNAPSHOT")

Test dependency in plugin’s dependencies

Now you have to add the dependency for the plugin to reuse at runtime.

Maven.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/pom.xml[]

+

<plugin>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+	<version>${spring-cloud-contract.version}</version>
+	<extensions>true</extensions>
+	<configuration>
+		<packageWithBaseClasses>com.example</packageWithBaseClasses>
+		<baseClassMappings>
+			<baseClassMapping>
+				<contractPackageRegex>.*intoxication.*</contractPackageRegex>
+				<baseClassFQN>com.example.intoxication.BeerIntoxicationBase</baseClassFQN>
+			</baseClassMapping>
+		</baseClassMappings>
+	</configuration>
+	<dependencies>
+		<dependency>
+			<groupId>com.example</groupId>
+			<artifactId>beer-common</artifactId>
+			<version>${project.version}</version>
+			<scope>compile</scope>
+		</dependency>
+	</dependencies>
+</plugin>

Gradle.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/build.gradle[]

-

Referencing classes in DSLs

Now you can reference your classes in your DSL. Example:

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[]

2.19 Pluggable architecture

There are cases where you have your contracts defined in other formats +

classpath "com.example:beer-common:0.0.1-SNAPSHOT"

+

Referencing classes in DSLs

Now you can reference your classes in your DSL. Example:

package contracts.beer.rest
+
+import com.example.ConsumerUtils
+import com.example.ProducerUtils
+import org.springframework.cloud.contract.spec.Contract
+
+Contract.make {
+	description("""
+Represents a successful scenario of getting a beer
+
+```
+given:
+	client is old enough
+when:
+	he applies for a beer
+then:
+	we'll grant him the beer
+```
+
+""")
+	request {
+		method 'POST'
+		url '/check'
+		body(
+				age: $(ConsumerUtils.oldEnough())
+		)
+		headers {
+			contentType(applicationJson())
+		}
+	}
+	response {
+		status 200
+		body("""
+			{
+				"status": "${value(ProducerUtils.ok())}"
+			}
+			""")
+		headers {
+			contentType(applicationJson())
+		}
+	}
+}

2.19 Pluggable architecture

There are cases where you have your contracts defined in other formats like YAML, RAML or PACT. On the other hand you’d like to profit from the test and stubs generation. It’s really easy to add your own implementation of either of those. Also you can customize the way tests are generated (for example you can generate diff --git a/single/spring-cloud-contract.html b/single/spring-cloud-contract.html index 56a2ff7cf5..9460c5f6c8 100644 --- a/single/spring-cloud-contract.html +++ b/single/spring-cloud-contract.html @@ -376,7 +376,9 @@ git merge --no-ff contract-change-pr git push origin master

Then we assume that your CI would run sth like ./mvnw clean deploy which would publish both the application and the stub artifcats.

Consumer side (Loan Issuance) final step

As a developer of the Loan Issuance service (a consumer of the Fraud Detection server):

merge branch to master

git checkout master
 git merge --no-ff contract-change-pr

work online

Now you can disable the offline work for Spring Cloud Contract Stub Runner and provide where the repository with your stubs is placed. At this moment the stubs of the server side will be automatically downloaded from Nexus / Artifactory. You can switch off the value of the workOffline parameter in your annotation. Below you can see an -example of achieving the same by changing the properties.

link:https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml[]

And that’s it!

2.1.5 Dependencies

The best way to add the dependencies is to just use the proper starter dependency.

For stub-runner use spring-cloud-starter-stub-runner and when you’re using a plugin just add +example of achieving the same by changing the properties.

stubrunner:
+  ids: 'com.example:http-server-dsl:+:stubs:8080'
+  repositoryRoot: http://repo.spring.io/libs-snapshot

And that’s it!

2.1.5 Dependencies

The best way to add the dependencies is to just use the proper starter dependency.

For stub-runner use spring-cloud-starter-stub-runner and when you’re using a plugin just add spring-cloud-starter-contract-verifier.

2.1.6 Additional links

Below you can find some resources related to Spring Cloud Contract Verifier and Stub Runner. Note that some can be outdated since the Spring Cloud Contract Verifier project is under constant development.

Spring Cloud Contract video

You can check out the video from the Warsaw JUG about Spring Cloud Contract:

Readings

2.1.7 Samples

Here you can find some samples.

2.2 FAQ

2.2.1 Why use Spring Cloud Contract Verifier and not X ?

For the time being Spring Cloud Contract Verifier is a JVM based tool. So it could be your first pick when you’re already creating software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make @@ -1410,13 +1412,71 @@ automatically for you.

}

2.5.2 Publishing stubs as JARs

The easiest approach would be to centralize the way stubs are kept. For example you can keep them as JARs in a Maven repository.

[Tip]Tip

For both Maven and Gradle the setup comes out of the box. But you can customize it if you want to.

Maven. 

<!-- First disable the default jar setup in the properties section-->
-link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer_with_restdocs/pom.xml[]
+<!-- we don't want the verifier to do a jar for us -->
+<spring.cloud.contract.verifier.skip>true</spring.cloud.contract.verifier.skip>
 
 <!-- Next add the assembly plugin to your build -->
-link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer_with_restdocs/pom.xml[]
+<!-- we want the assembly plugin to generate the JAR -->
+<plugin>
+	<groupId>org.apache.maven.plugins</groupId>
+	<artifactId>maven-assembly-plugin</artifactId>
+	<executions>
+		<execution>
+			<id>stub</id>
+			<phase>prepare-package</phase>
+			<goals>
+				<goal>single</goal>
+			</goals>
+			<inherited>false</inherited>
+			<configuration>
+				<attach>true</attach>
+				<descriptor>${basedir}/src/assembly/stub.xml</descriptor>
+			</configuration>
+		</execution>
+	</executions>
+</plugin>
 
 <!-- Finally setup your assembly. Below you can find the contents of src/main/assembly/stub.xml -->
-link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer_with_restdocs/src/assembly/stub.xml[]

+<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> + <id>stubs</id> + <formats> + <format>jar</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + <fileSets> + <fileSet> + <directory>src/main/java</directory> + <outputDirectory>/</outputDirectory> + <includes> + <include>**com/example/model/*.*</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.build.directory}/classes</directory> + <outputDirectory>/</outputDirectory> + <includes> + <include>**com/example/model/*.*</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.build.directory}/snippets/stubs</directory> + <outputDirectory>META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings</outputDirectory> + <includes> + <include>**/*</include> + </includes> + </fileSet> + <fileSet> + <directory>${basedir}/src/test/resources/contracts</directory> + <outputDirectory>META-INF/${project.groupId}/${project.artifactId}/${project.version}/contracts</outputDirectory> + <includes> + <include>**/*.groovy</include> + </includes> + </fileSet> + </fileSets> +</assembly>

Gradle. 

ext {
 	contractsDir = file("mappings")
@@ -3429,18 +3489,217 @@ got the name of the contract file WithList.groovy p
 contract had index 1 in the list of contracts in the file).

[Tip]Tip

As you can see it’s much better if you name your contracts since then your tests are far more meaningful.

2.18 Customization

2.18.1 Extending the DSL

It is possible to provide your own functions to the DSL. The key requirement for this feature was to maintain the static compatibility. Below you will be able to see an example -of:

  • creation of a JAR with reusable classes
  • referencing of these classes in the DSLs

The full example can be found here.

Common JAR

Below you can find three classes that we will reuse in the DSLs.

PatternUtils contains functions used by both the consumer and the producer.

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/common/src/main/java/com/example/PatternUtils.java[]

ConsumerUtils contains functions used by the consumer.

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/common/src/main/java/com/example/ConsumerUtils.java[]

ProducerUtils contains functions used by the producer.

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/common/src/main/java/com/example/ProducerUtils.java[]

Adding the dependency to project

In order for the plugins and IDE to be able to reference the common JAR classes you need +of:

  • creation of a JAR with reusable classes
  • referencing of these classes in the DSLs

The full example can be found here.

Common JAR

Below you can find three classes that we will reuse in the DSLs.

PatternUtils contains functions used by both the consumer and the producer.

package com.example;
+
+import java.util.regex.Pattern;
+
+/**
+ * If you want to use {@link Pattern} directly in your tests
+ * then you can create a class resembling this one. It can
+ * contain all the {@link Pattern} you want to use in the DSL.
+ *
+ * <pre>
+ * {@code
+ * request {
+ *     body(
+ *         [ age: $(c(PatternUtils.oldEnough()))]
+ *     )
+ * }
+ * </pre>
+ *
+ * Notice that we're using both {@code $()} for dynamic values
+ * and {@code c()} for the consumer side.
+ *
+ * @author Marcin Grzejszczak
+ */
+//tag::impl[]
+public class PatternUtils {
+
+	public static String tooYoung() {
+		//remove::start[]
+		return "[0-1][0-9]";
+		//remove::end[return]
+	}
+
+	public static Pattern oldEnough() {
+		//remove::start[]
+		return Pattern.compile("[2-9][0-9]");
+		//remove::end[return]
+	}
+
+	/**
+	 * Makes little sense but it's just an example ;)
+	 */
+	public static Pattern ok() {
+		//remove::start[]
+		return Pattern.compile("OK");
+		//remove::end[return]
+	}
+}
+//end::impl[]

ConsumerUtils contains functions used by the consumer.

package com.example;
+
+import org.springframework.cloud.contract.spec.internal.ClientDslProperty;
+
+/**
+ * DSL Properties passed to the DSL from the consumer's perspective.
+ * That means that on the input side {@code Request} for HTTP
+ * or {@code Input} for messaging you can have a regular expression.
+ * On the {@code Response} for HTTP or {@code Output} for messaging
+ * you have to have a concrete value.
+ *
+ * @author Marcin Grzejszczak
+ */
+//tag::impl[]
+public class ConsumerUtils {
+	/**
+	 * Consumer side property. By using the {@link ClientDslProperty}
+	 * you can omit most of boilerplate code from the perspective
+	 * of dynamic values. Example
+	 *
+	 * <pre>
+	 * {@code
+	 * request {
+	 *     body(
+	 *         [ age: $(ConsumerUtils.oldEnough())]
+	 *     )
+	 * }
+	 * </pre>
+	 *
+	 * That way it's in the implementation that we decide what value we will pass to the consumer
+	 * and which one to the producer.
+	 *
+	 * @author Marcin Grzejszczak
+	 */
+	public static ClientDslProperty oldEnough() {
+		//remove::start[]
+		// this example is not the best one and
+		// theoretically you could just pass the regex instead of `ServerDslProperty` but
+		// it's just to show some new tricks :)
+		return new ClientDslProperty(PatternUtils.oldEnough(), 40);
+		//remove::end[return]
+	}
+
+}
+//end::impl[]

ProducerUtils contains functions used by the producer.

package com.example;
+
+import org.springframework.cloud.contract.spec.internal.ServerDslProperty;
+
+/**
+ * DSL Properties passed to the DSL from the producer's perspective.
+ * That means that on the input side {@code Request} for HTTP
+ * or {@code Input} for messaging you have to have a concrete value.
+ * On the {@code Response} for HTTP or {@code Output} for messaging
+ * you can have a regular expression.
+ *
+ * @author Marcin Grzejszczak
+ */
+//tag::impl[]
+public class ProducerUtils {
+
+	/**
+	 * Producer side property. By using the {@link ProducerUtils}
+	 * you can omit most of boilerplate code from the perspective
+	 * of dynamic values. Example
+	 *
+	 * <pre>
+	 * {@code
+	 * response {
+	 *     body(
+	 *         [ status: $(ProducerUtils.ok())]
+	 *     )
+	 * }
+	 * </pre>
+	 *
+	 * That way it's in the implementation that we decide what value we will pass to the consumer
+	 * and which one to the producer.
+	 */
+	public static ServerDslProperty ok() {
+		// this example is not the best one and
+		// theoretically you could just pass the regex instead of `ServerDslProperty` but
+		// it's just to show some new tricks :)
+		return new ServerDslProperty( PatternUtils.ok(), "OK");
+	}
+}
+//end::impl[]

Adding the dependency to project

In order for the plugins and IDE to be able to reference the common JAR classes you need to pass the dependency to your project.

Test dependency in project’s dependencies

First add the common jar dependency as a test dependency. That way since your contracts files are available at test resources path, automatically the common jar classes will be visible in your Groovy files.

Maven.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/pom.xml[]

+

<dependency>
+	<groupId>com.example</groupId>
+	<artifactId>beer-common</artifactId>
+	<version>${project.version}</version>
+	<scope>test</scope>
+</dependency>

Gradle.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/build.gradle[]

+

testCompile("com.example:beer-common:0.0.1-SNAPSHOT")

Test dependency in plugin’s dependencies

Now you have to add the dependency for the plugin to reuse at runtime.

Maven.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/pom.xml[]

+

<plugin>
+	<groupId>org.springframework.cloud</groupId>
+	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
+	<version>${spring-cloud-contract.version}</version>
+	<extensions>true</extensions>
+	<configuration>
+		<packageWithBaseClasses>com.example</packageWithBaseClasses>
+		<baseClassMappings>
+			<baseClassMapping>
+				<contractPackageRegex>.*intoxication.*</contractPackageRegex>
+				<baseClassFQN>com.example.intoxication.BeerIntoxicationBase</baseClassFQN>
+			</baseClassMapping>
+		</baseClassMappings>
+	</configuration>
+	<dependencies>
+		<dependency>
+			<groupId>com.example</groupId>
+			<artifactId>beer-common</artifactId>
+			<version>${project.version}</version>
+			<scope>compile</scope>
+		</dependency>
+	</dependencies>
+</plugin>

Gradle.  -

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/build.gradle[]

-

Referencing classes in DSLs

Now you can reference your classes in your DSL. Example:

link:https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/master/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[]

2.19 Pluggable architecture

There are cases where you have your contracts defined in other formats +

classpath "com.example:beer-common:0.0.1-SNAPSHOT"

+

Referencing classes in DSLs

Now you can reference your classes in your DSL. Example:

package contracts.beer.rest
+
+import com.example.ConsumerUtils
+import com.example.ProducerUtils
+import org.springframework.cloud.contract.spec.Contract
+
+Contract.make {
+	description("""
+Represents a successful scenario of getting a beer
+
+```
+given:
+	client is old enough
+when:
+	he applies for a beer
+then:
+	we'll grant him the beer
+```
+
+""")
+	request {
+		method 'POST'
+		url '/check'
+		body(
+				age: $(ConsumerUtils.oldEnough())
+		)
+		headers {
+			contentType(applicationJson())
+		}
+	}
+	response {
+		status 200
+		body("""
+			{
+				"status": "${value(ProducerUtils.ok())}"
+			}
+			""")
+		headers {
+			contentType(applicationJson())
+		}
+	}
+}

2.19 Pluggable architecture

There are cases where you have your contracts defined in other formats like YAML, RAML or PACT. On the other hand you’d like to profit from the test and stubs generation. It’s really easy to add your own implementation of either of those. Also you can customize the way tests are generated (for example you can generate diff --git a/spring-cloud-contract.html b/spring-cloud-contract.html index e4d2d96c89..aa81cb28d2 100644 --- a/spring-cloud-contract.html +++ b/spring-cloud-contract.html @@ -4,7 +4,7 @@ - + spring-cloud-contract