Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to setup for simultaneous provider and consumer? #176

Open
embs opened this issue Aug 8, 2018 · 2 comments
Open

How to setup for simultaneous provider and consumer? #176

embs opened this issue Aug 8, 2018 · 2 comments

Comments

@embs
Copy link

embs commented Aug 8, 2018

Hello!

Thank you very much for Pact. It's awesome.

This is more of a conceptual question than a bug report, so I'm not providing much code but I would happily arrange it if necessary. Also, I guess this is a common use case but I wasn't able to find examples for it -- that's why I'm filing this issue. Hopefully, it can be addressed by only referring to some examples.

I'm using Pact for testing a services architecture like this:

service A --consumes--> service B --consumes--> service C

My intended approach is writing tests by hand only for service A and having Pact to verify proper behavior for services B and C based on generated pacts. I was able to generate the pact a-b.json from A's tests execution and now I want to use it for verifying B while generating b-c.json pact.

My attempt for this looks like this:

# ./spec/service_consumers/pact_helper.rb inside B

Pact.service_provider 'B' do
  honours_pact_with 'A' do
    pact_uri 'a-b.json'
  end
end

Pact.service_consumer 'B' do
  has_pact_with 'C' do
    mock_service :c_service do
      port 1234
    end
  end
end

# This is how I accomplished mocking B -> C requests
c_service = Pact.consumer_world.consumer_contract_builders.first
c_service.given('some state')
  .upon_receiving('some request')
  .with(method: :get, path: '/resource')
  .will_respond_with(status: 200, body: [])

# This is for writing `b-c.json` so I can verify C with Pact
RSpec.configure do |config|
  config.after(:suite) do
    Pact.consumer_world.consumer_contract_builders.each { |c| c.write_pact }
  end
end

This seems to satisfy my use case but I was expecting a cleaner way for mocking and writing the pact file. Specifically, I feel I'm missing what happens within RSpec specs when we assign pact: true: disposal of c_service instance on the fly and automatically written pact file.

I wonder if this is a common use case and how to appropriately tackle it. Hope you can guide me in the right direction.

Thanks again,
Matheus

@bethesque
Copy link
Member

bethesque commented Aug 9, 2018

This setup makes me feel a bit nervous because it's all so very highly coupled. But I'll work with you on it. A little spike codebase would really help work this out. Are you requiring "pact/consumer/rspec" anywhere? That's the thing that hooks up the after suite hooks.

If you do this, it should make your consumer contract builder available by name in the provider state set up blocks:

Pact.configure do | config |
    config.include Pact::Consumer::RSpec
end

@babelian
Copy link

babelian commented Jan 4, 2019

I had a similar scenario, but opted to just use allow() to stub service C in the provider_state setup (of the A<>B pact verification). As long as Service B has complete specs, we still get coverage when it runs its own specs (with Pact mock servers for B->C).

I've just tried switching it out for the method above, but found that because Pact raises an error if the request does not happen its easier to use allow() which is indifferent about the order of calls or whether they happen at all. To use Pact within the provider one would either have to make very granular provider states or perhaps wait for access to v3 params to determine which things to stub (at all a bit messy).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants