<commit_before># Pact

Define a pact between service consumers and providers, enabling "consumer driven contract" testing.

Pact provides an RSpec DSL for service consumers to define the HTTP requests they will make to a service provider and the HTTP responses they expect back. These expectations are used in the consumers specs to provide a mock service provider. The interactions are recorded, and played back in the service provider specs to ensure the service provider actually does provide the response the consumer expects.

This allows testing of both sides of an integration point using fast unit tests.

This gem is inspired by the concept of "Consumer driven contracts". See http://martinfowler.com/articles/consumerDrivenContracts.html for more information.

Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/realestate-com-au/pact.png)](https://travis-ci.org/realestate-com-au/pact)

## Features
* A service is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
* "Provider states" (similar to fixtures) allow the same request to be made with a different expected response.
* Consumers specify only the fields they are interested in, allowing a provider to return more fields without breaking the pact. This allows a provider to have a different pact with a different consumer, and know which fields each cares about in a given response.
* Rake tasks allow pacts to be verified against a service provider codebase.
* Different versions of a consumer/provider pairs can be easily tested against each other, allowing confidence when deploying new versions of each (see the pact_broker and pact_broker-client gems).
* Autogenerated API documentation - need we say more?

## How does it work?

1. In the specs for the provider facing code in the consumer project, expectations are set up on a mock service provider.
1. When the specs are run, the requests, and their expected responses, are written to a "pact" file.
1. The requests in the pact file are later replayed against the provider, and the actual responses are checked to make sure they match the expected responses.

## Why is developing and testing with pacts better than using integration tests?

* Faster execution.
* Reliable responses from mock service provider reduce likelihood of flakey tests.
* Only one component is being tested at a time, making the causes of test failures easier to identify.
* Design of service provider is improved by considering first how the data is actually going to be used, rather than how it is most easily retrieved and serialised.
* No need to manage starting, stopping and fixture set up for multiple applications during a test run.

## Contact

* Twitter: [@pact_up](https://twitter.com/pact_up)
* Google users group: https://groups.google.com/forum/#!forum/pact-support

## Installation

Put it in your Gemfile. You know how.

## Usage

### Service Consumer project

#### 1. Start with you model

Imagine a model class that looks something like this. The attributes for a Something live on a remote server, and will need to be retrieved by an HTTP call.

```ruby
class Something
  attr_reader :name

  def initialize name
    @name = name
  end

  def == other
    other.is_a?(Something) && other.name == name
  end
end
```

#### 2. Create a skeleton client class

Imagine a service provider client class that looks something like this.

```ruby
class MyServiceProviderClient
  include HTTParty
  base_uri 'http://my-service'

  def get_something
    # Yet to be implemented because we're doing Test First Development...
  end
end
```
#### 3. Configure the mock server

The following code will create a mock service on localhost:1234 which will respond to your application's queries over HTTP as if it were the real "My Service Provider" app. It also creats a mock service provider object which you will use to set up your expectations. The method name to access the mock service provider will be what ever name you give as the service argument - in this case "my_service_provider"


```ruby
# In /spec/service_providers/pact_helper.rb

require 'pact/consumer/rspec'

Pact.service_consumer "My Service Consumer" do
  has_pact_with "My Service Provider" do
    mock_service :my_service_provider do
      port 1234
    end
  end
end
```

#### 4. Write a failing spec for the client

```ruby
# In /spec/service_providers/my_service_provider_client_spec.rb

# Use the :pact => true describe metadata to include all the pact generation functionality in your spec.
describe MyServiceProviderClient, :pact => true do

  before do
    # Configure your client to point to the stub service on localhost using the port you have specified
    MyServiceProviderClient.base_uri 'localhost:1234'
  end

  subject { MyServiceProviderClient.new }

  describe "get_something" do

    before do
      my_service_provider.given("something exists").
        upon_receiving("a request for something").with(method: :get, path: '/something').
        will_respond_with(
          status: 200,
          headers: {'Content-Type' => 'application/json'},
          body: {name: 'A small something'} )
    end

    it "returns a Something" do
      expect(subject.get_something).to eq(Something.new('A small something'))
    end

  end

end
```

#### 5. Run the specs

Running the consumer spec will generate a pact file in the configured pact dir (spec/pacts by default).
Logs will be output to the configured log dir that can be useful when diagnosing problems.

Of course, the above specs will fail because the client method is not implemented, so next, implement your client methods.

#### 6. Implement the client methods

```ruby
class MyServiceProviderClient
  include HTTParty
  base_uri 'http://my-service'

  def get_something
    name = JSON.parse(self.class.get("/something").body)['name']
    Something.new(name)
  end
end
```

#### 7. Run the specs again.

Green! You now have a pact file that can be used to verify your expectations in the provider project.
Now, rinse and repeat for ALL the likely status codes that may be returned (we recommend 404, 500 and 401/403 if there is authorisation.)

### Service Provider project

#### 1. Create the skeleton API classes

Create your API class using the framework of your choice - leave the methods unimplemented, we're doing Test First Develoment, remember?

#### 2. Tell your provider that it needs to honour the pact file you made earlier

Require "pact/tasks" in your Rakefile.

```ruby
# In Rakefile
require 'pact/tasks'
```

Create a `pact_helper.rb` in your service provider project. The file must be called pact_helper.rb, however there is some flexibility in where it can be stored. The recommended place is `specs/service_consumers/pact_helper.rb`.

See the [Provider](/documentation.md#provider) section of the Configuration documentation for more information.

```ruby
# In specs/service_consumers/pact_helper.rb

require 'pact/provider/rspec'

Pact.service_provider "My Service Provider" do

  app { MyApp.new } # Optional, loads app from config.ru by default

  honours_pact_with 'My Service Consumer' do

    # This example points to a local file, however, on a real project with a continuous
    # integration box, you would publish your pacts as artifacts,
    # and point the pact_uri to the pact published by the last successful build.

    pact_uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
  end
end<commit_msg>Update link to provider documentation<commit_after># Pact

Define a pact between service consumers and providers, enabling "consumer driven contract" testing.

Pact provides an RSpec DSL for service consumers to define the HTTP requests they will make to a service provider and the HTTP responses they expect back. These expectations are used in the consumers specs to provide a mock service provider. The interactions are recorded, and played back in the service provider specs to ensure the service provider actually does provide the response the consumer expects.

This allows testing of both sides of an integration point using fast unit tests.

This gem is inspired by the concept of "Consumer driven contracts". See http://martinfowler.com/articles/consumerDrivenContracts.html for more information.

Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/realestate-com-au/pact.png)](https://travis-ci.org/realestate-com-au/pact)

## Features
* A service is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
* "Provider states" (similar to fixtures) allow the same request to be made with a different expected response.
* Consumers specify only the fields they are interested in, allowing a provider to return more fields without breaking the pact. This allows a provider to have a different pact with a different consumer, and know which fields each cares about in a given response.
* Rake tasks allow pacts to be verified against a service provider codebase.
* Different versions of a consumer/provider pairs can be easily tested against each other, allowing confidence when deploying new versions of each (see the pact_broker and pact_broker-client gems).
* Autogenerated API documentation - need we say more?

## How does it work?

1. In the specs for the provider facing code in the consumer project, expectations are set up on a mock service provider.
1. When the specs are run, the requests, and their expected responses, are written to a "pact" file.
1. The requests in the pact file are later replayed against the provider, and the actual responses are checked to make sure they match the expected responses.

## Why is developing and testing with pacts better than using integration tests?

* Faster execution.
* Reliable responses from mock service provider reduce likelihood of flakey tests.
* Only one component is being tested at a time, making the causes of test failures easier to identify.
* Design of service provider is improved by considering first how the data is actually going to be used, rather than how it is most easily retrieved and serialised.
* No need to manage starting, stopping and fixture set up for multiple applications during a test run.

## Contact

* Twitter: [@pact_up](https://twitter.com/pact_up)
* Google users group: https://groups.google.com/forum/#!forum/pact-support

## Installation

Put it in your Gemfile. You know how.

## Usage

### Service Consumer project

#### 1. Start with you model

Imagine a model class that looks something like this. The attributes for a Something live on a remote server, and will need to be retrieved by an HTTP call.

```ruby
class Something
  attr_reader :name

  def initialize name
    @name = name
  end

  def == other
    other.is_a?(Something) && other.name == name
  end
end
```

#### 2. Create a skeleton client class

Imagine a service provider client class that looks something like this.

```ruby
class MyServiceProviderClient
  include HTTParty
  base_uri 'http://my-service'

  def get_something
    # Yet to be implemented because we're doing Test First Development...
  end
end
```
#### 3. Configure the mock server

The following code will create a mock service on localhost:1234 which will respond to your application's queries over HTTP as if it were the real "My Service Provider" app. It also creats a mock service provider object which you will use to set up your expectations. The method name to access the mock service provider will be what ever name you give as the service argument - in this case "my_service_provider"


```ruby
# In /spec/service_providers/pact_helper.rb

require 'pact/consumer/rspec'

Pact.service_consumer "My Service Consumer" do
  has_pact_with "My Service Provider" do
    mock_service :my_service_provider do
      port 1234
    end
  end
end
```

#### 4. Write a failing spec for the client

```ruby
# In /spec/service_providers/my_service_provider_client_spec.rb

# Use the :pact => true describe metadata to include all the pact generation functionality in your spec.
describe MyServiceProviderClient, :pact => true do

  before do
    # Configure your client to point to the stub service on localhost using the port you have specified
    MyServiceProviderClient.base_uri 'localhost:1234'
  end

  subject { MyServiceProviderClient.new }

  describe "get_something" do

    before do
      my_service_provider.given("something exists").
        upon_receiving("a request for something").with(method: :get, path: '/something').
        will_respond_with(
          status: 200,
          headers: {'Content-Type' => 'application/json'},
          body: {name: 'A small something'} )
    end

    it "returns a Something" do
      expect(subject.get_something).to eq(Something.new('A small something'))
    end

  end

end
```

#### 5. Run the specs

Running the consumer spec will generate a pact file in the configured pact dir (spec/pacts by default).
Logs will be output to the configured log dir that can be useful when diagnosing problems.

Of course, the above specs will fail because the client method is not implemented, so next, implement your client methods.

#### 6. Implement the client methods

```ruby
class MyServiceProviderClient
  include HTTParty
  base_uri 'http://my-service'

  def get_something
    name = JSON.parse(self.class.get("/something").body)['name']
    Something.new(name)
  end
end
```

#### 7. Run the specs again.

Green! You now have a pact file that can be used to verify your expectations in the provider project.
Now, rinse and repeat for ALL the likely status codes that may be returned (we recommend 404, 500 and 401/403 if there is authorisation.)

### Service Provider project

#### 1. Create the skeleton API classes

Create your API class using the framework of your choice - leave the methods unimplemented, we're doing Test First Develoment, remember?

#### 2. Tell your provider that it needs to honour the pact file you made earlier

Require "pact/tasks" in your Rakefile.

```ruby
# In Rakefile
require 'pact/tasks'
```

Create a `pact_helper.rb` in your service provider project. The file must be called pact_helper.rb, however there is some flexibility in where it can be stored. The recommended place is `specs/service_consumers/pact_helper.rb`.

See the [Provider](documentation/configuration.md#provider) section of the Configuration documentation for more information.

```ruby
# In specs/service_consumers/pact_helper.rb

require 'pact/provider/rspec'

Pact.service_provider "My Service Provider" do

  app { MyApp.new } # Optional, loads app from config.ru by default

  honours_pact_with 'My Service Consumer' do

    # This example points to a local file, however, on a real project with a continuous
    # integration box, you would publish your pacts as artifacts,
    # and point the pact_uri to the pact published by the last successful build.

    pact_uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
  end
end
{'fraction_non_alphanumeric': 0.06499634478633615, 'fraction_numerical': 0.005183757559646441, 'mean_word_length': 4.134083930399181, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1808397', 'n_tokens_mistral': 4070, 'n_tokens_neox': 3807, 'n_words': 1991}