<?xml version="1.0" encoding="UTF-8"?>
<project 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" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>au.com.dius</groupId>
  <artifactId>pact-jvm-provider-spring_2.12</artifactId>
  <version>3.6.15</version>
  <name>pact-jvm-provider-spring_2.12</name>
  <description># Pact Spring/JUnit runner

## Overview
Library provides ability to play contract tests against a provider using Spring &amp;amp; JUnit.
This library is based on and references the JUnit package, so see the [Pact JUnit 4](../pact-jvm-provider-junit) or [Pact JUnit 5](../pact-jvm-provider-junit5) providers for more details regarding configuration using JUnit.

Supports:

- Standard ways to load pacts from folders and broker

- Easy way to change assertion strategy

- Spring Test MockMVC Controllers and ControllerAdvice using MockMvc standalone setup.

- MockMvc debugger output

- Multiple @State runs to test a particular Provider State multiple times

- **au.com.dius.pact.provider.junit.State** custom annotation - before each interaction that requires a state change,
all methods annotated by `@State` with appropriate the state listed will be invoked.

**NOTE:** For publishing provider verification results to a pact broker, make sure the Java system property `pact.provider.version`
is set with the version of your provider. 

## Example of MockMvc test

```java
    @RunWith(RestPactRunner.class) // Custom pact runner, child of PactRunner which runs only REST tests
    @Provider(&amp;quot;myAwesomeService&amp;quot;) // Set up name of tested provider
    @PactFolder(&amp;quot;pacts&amp;quot;) // Point where to find pacts (See also section Pacts source in documentation)
    public class ContractTest {
        //Create an instance of your controller.  We cannot autowire this as we&amp;apos;re not using (and don&amp;apos;t want to use)  a Spring test runner.
        @InjectMocks
        private AwesomeController awesomeController = new AwesomeController();

        //Mock your service logic class.  We&amp;apos;ll use this to create scenarios for respective provider states.
        @Mock
        private AwesomeBusinessLogic awesomeBusinessLogic;

        //Create an instance of your controller advice (if you have one).  This will be passed to the MockMvcTarget constructor to be wired up with MockMvc.
        @InjectMocks
        private AwesomeControllerAdvice awesomeControllerAdvice = new AwesomeControllerAdvice();

        //Create a new instance of the MockMvcTarget and annotate it as the TestTarget for PactRunner
        @TestTarget
        public final MockMvcTarget target = new MockMvcTarget();

        @Before //Method will be run before each test of interaction
        public void before() {
            //initialize your mocks using your mocking framework
            MockitoAnnotations.initMocks(this);

            //configure the MockMvcTarget with your controller and controller advice
            target.setControllers(awesomeController);
            target.setControllerAdvice(awesomeControllerAdvice);
        }

        @State(&amp;quot;default&amp;quot;, &amp;quot;no-data&amp;quot;) // Method will be run before testing interactions that require &amp;quot;default&amp;quot; or &amp;quot;no-data&amp;quot; state
        public void toDefaultState() {
            target.setRunTimes(3);  //let&amp;apos;s loop through this state a few times for a 3 data variants
            when(awesomeBusinessLogic.getById(any(UUID.class)))
                .thenReturn(myTestHelper.generateRandomReturnData(UUID.randomUUID(), ExampleEnum.ONE))
                .thenReturn(myTestHelper.generateRandomReturnData(UUID.randomUUID(), ExampleEnum.TWO))
                .thenReturn(myTestHelper.generateRandomReturnData(UUID.randomUUID(), ExampleEnum.THREE));
        }

        @State(&amp;quot;error-case&amp;quot;)
        public void SingleUploadExistsState_Success() {
            target.setRunTimes(1); //tell the runner to only loop one time for this state
            
            //you might want to throw exceptions to be picked off by your controller advice
            when(awesomeBusinessLogic.getById(any(UUID.class)))
                .then(i -&amp;gt; { throw new NotCoolException(i.getArgumentAt(0, UUID.class).toString()); });
        }
    }
```

## Using a Spring runner (version 3.5.7+)

You can use `SpringRestPactRunner` instead of the default Pact runner to use the Spring test annotations. This will
allow you to inject or mock spring beans.

For example:

```java
@RunWith(SpringRestPactRunner.class)
@Provider(&amp;quot;pricing&amp;quot;)
@PactBroker(protocol = &amp;quot;https&amp;quot;, host = &amp;quot;${pactBrokerHost}&amp;quot;, port = &amp;quot;443&amp;quot;,
authentication = @PactBrokerAuth(username = &amp;quot;${pactBrokerUser}&amp;quot;, password = &amp;quot;${pactBrokerPassword}&amp;quot;))
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class PricingServiceProviderPactTest {

  @MockBean
  private ProductClient productClient;  // This will replace the bean with a mock in the application context

  @TestTarget
  @SuppressWarnings(value = &amp;quot;VisibilityModifier&amp;quot;)
  public final Target target = new HttpTarget(8091);

  @State(&amp;quot;Product X010000021 exists&amp;quot;)
  public void setupProductX010000021() throws IOException {
    reset(productClient);
    ProductBuilder product = new ProductBuilder()
      .withProductCode(&amp;quot;X010000021&amp;quot;);
    when(productClient.fetch((Set&amp;lt;String&amp;gt;) argThat(contains(&amp;quot;X010000021&amp;quot;)), any())).thenReturn(product);
  }

  @State(&amp;quot;the product code X00001 can be priced&amp;quot;)
  public void theProductCodeX00001CanBePriced() throws IOException {
    reset(productClient);
    ProductBuilder product = new ProductBuilder()
      .withProductCode(&amp;quot;X00001&amp;quot;);
    when(productClient.find((Set&amp;lt;String&amp;gt;) argThat(contains(&amp;quot;X00001&amp;quot;)), any())).thenReturn(product);
  }

}
```

### Using Spring Context Properties (version 3.5.14+)

From version 3.5.14 onwards, the SpringRestPactRunner will look up any annotation expressions (like `${pactBrokerHost}`)
above) from the Spring context. For Springboot, this will allow you to define the properties in the application test properties.

For instance, if you create the following `application.yml` in the test resources:

```yaml
pactbroker:
  host: &amp;quot;your.broker.local&amp;quot;
  port: &amp;quot;443&amp;quot;
  protocol: &amp;quot;https&amp;quot;
  auth:
    username: &amp;quot;&amp;lt;your broker username&amp;gt;&amp;quot;
    password: &amp;quot;&amp;lt;your broker password&amp;gt;&amp;quot;

```

Then you can use the defaults on the `@PactBroker` annotation.

```java
@RunWith(SpringRestPactRunner.class)
@Provider(&amp;quot;My Service&amp;quot;)
@PactBroker(
  authentication =  @PactBrokerAuth(username = &amp;quot;${pactbroker.auth.username}&amp;quot;, password = &amp;quot;${pactbroker.auth.password}&amp;quot;)
)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PactVerificationTest {

```

### Using a random port with a Springboot test (version 3.5.14+)

If you use a random port in a springboot test (by setting `SpringBootTest.WebEnvironment.RANDOM_PORT`), you can use the
`SpringBootHttpTarget` which will get the application port from the spring application context.

For example:

```java
@RunWith(SpringRestPactRunner.class)
@Provider(&amp;quot;My Service&amp;quot;)
@PactBroker
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PactVerificationTest {

  @TestTarget
  public final Target target = new SpringBootHttpTarget();

}
```
</description>
  <url>https://github.com/DiUS/pact-jvm</url>
  <licenses>
    <license>
      <name>Apache 2</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <developers>
    <developer>
      <id>thetrav</id>
      <name>Travis Dixon</name>
      <email>the.trav@gmail.com</email>
    </developer>
    <developer>
      <id>rholshausen</id>
      <name>Ronald Holshausen</name>
      <email>rholshausen@dius.com.au</email>
    </developer>
  </developers>
  <scm>
    <connection>https://github.com/DiUS/pact-jvm.git</connection>
    <url>https://github.com/DiUS/pact-jvm</url>
  </scm>
  <dependencies>
    <dependency>
      <groupId>au.com.dius</groupId>
      <artifactId>pact-jvm-provider-junit_2.12</artifactId>
      <version>3.6.15</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>1.5.16.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.19.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-joda</artifactId>
      <version>2.6.4</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest</artifactId>
      <version>2.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.spockframework</groupId>
      <artifactId>spock-core</artifactId>
      <version>1.3-groovy-2.5</version>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <artifactId>*</artifactId>
          <groupId>org.codehaus.groovy</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>net.bytebuddy</groupId>
      <artifactId>byte-buddy</artifactId>
      <version>1.9.13</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.objenesis</groupId>
      <artifactId>objenesis</artifactId>
      <version>3.0.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.codehaus.groovy</groupId>
      <artifactId>groovy</artifactId>
      <version>2.5.6</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>1.5.16.RELEASE</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
