Jump to content

The ultimate community for Ruby on Rails developers.


Photo

How to test something is submitted to a 3rd party with Cucumber

cucumber

  • Please log in to reply
7 replies to this topic

#1 Senktec

Senktec

    Passenger

  • Members
  • 6 posts
  • LocationUK

Posted 25 October 2013 - 09:48 PM

I have a basic contact form on a website. When the user submits a message, instead of saving the message locally, I want the message to be sent directly to a third party and a 'message sent' response posted back to the user if it was successful. How should I best test this scenario with Cucumber without submitting test data to the third party?
 
My scenario looks like this:
Scenario: Submitting a message
  Given I am on the contact page
  When I submit a message
  Then I should see message submitted
  And the message should be created at ThirdParty
Lets say I have an API that allows me to submit a message to the third party by doing:
ThirdParty.create_message('my message')
I could implement this situation in RSpec/Capybara by mocking. Here, I am setting the expectation that create_message will be called on ThirdParty and returning a canned response.
visit message_path
ThirdParty.should_receive(:create_message).with('my message').and_return(true)
fill_in 'message', with: 'my message'
click_on 'submit'
page.should have_content 'message submitted'
The mock needs to be setup before the submit action is performed. However, in the Cucumber scenario the message created should be checked after the submit action to properly follow the Given/When/Then pattern.
Given(/^I am on the contact page$/) do
    visit message_path
end

When(/^I submit a message$/) do
    # TODO mock/stub create_message
    fill_in 'message', with: 'my message'
    click_on 'submit'
end

Then(/^I should see message submitted$/) do
    page.should have_content 'message submitted'
end

Then(/^the message should be created at ThirdParty$/) do
    # TODO check message created
end
How should I implement the Cucumber steps? Or how should I re-write the Cucumber scenarios to best handle this?


#2 Ohm

Ohm

    Guard

  • Members
  • 179 posts
  • LocationCopenhagen

Posted 26 October 2013 - 10:17 AM

You could probably use VCR (https://github.com/vcr/vcr) to record the interaction with the third party. That way you'll only test it once, and then just use the recording for all subsequent tests, not having to contact the third party doing spec runs.


Blog: http://ohm.sh | Twitter: madsohm


#3 Senktec

Senktec

    Passenger

  • Members
  • 6 posts
  • LocationUK

Posted 28 October 2013 - 04:06 PM

Hi Ohm. Thanks for the response. I'd not looked into VCR before. Presumably the recording would need to be played out during the "When" step, so I don't see how this helps me check the message has been created in the "Then" step?



#4 stevieing

stevieing

    Dispatcher

  • Members
  • 40 posts

Posted 29 October 2013 - 09:28 AM

I don't know if I am missing something but what kind of message are you sending; email or http response?



#5 Senktec

Senktec

    Passenger

  • Members
  • 6 posts
  • LocationUK

Posted 29 October 2013 - 10:09 AM

Hi stevieing. HTTP request, but I think either could be appropriate. I'm trying to understand how best to write and implement these kind of scenarios in Cucumber, as I can't find any good examples at the moment.



#6 stevieing

stevieing

    Dispatcher

  • Members
  • 40 posts

Posted 29 October 2013 - 11:32 AM

If you are testing emails then use the email_spec gem. https://github.com/bmabey/email-spec

 

Looking at your original scenario seems to suggests "the message should be created at ThirdParty" step is going to be an smtp rather than a http response.

 

It sounds to me like you are looking for a better insight into Cucumber itself. For that I would recommend the cucumber book from the pragmatic programmer. I found it invaluable.

Hope that helps.

 

You should not be mocking or stubbing create_message as you are testing the behaviour of your application. Click on submit should cause that method to be called. The only thing you should mock is the third party email server and setting ActionMailer.delivery_method to :test sorts that for you.

 

Hope that helps

 

Steve.


  • james likes this

#7 Senktec

Senktec

    Passenger

  • Members
  • 6 posts
  • LocationUK

Posted 05 November 2013 - 08:02 PM

Hi Stevieing. Thanks for your suggestions. I think perhaps the thing I've been missing is that setting ActionMailer.deliver_method to :test intercepts and stores the emails sent in the "When" step, and allows checks to be performed on the stored emails in the "Then" step. As I understand it, the emails are stored ActionMailer::Base.deliveries array and the email-spec gem provides some helpers and convenient ways of testing against them from within Cucumber.

 

Would it make sense to take the same approach with other kinds of requests? For example, an http request could be "played" through in the "When" step, the params we are passing would be stored, and we could check against the content submitted in the "Then" step.

 

If "ThirdParty" is maintained externally to the app, potentially with complicated requests to the outside world, would you still be against stubbing/mocking the method call?

 

It seems I could stub the create_message method call in the "When" step and store the params passed. Then, in the "Then" step, I could test against these params to check the correct data was passed. The following example seems reasonable to me, but I can't find examples of others doing anything like this.

Given(/^I am on the contact page$/) do
  visit message_path
end

When(/^I submit a message$/) do
  @message_submitted = nil
  ThirdParty.stub(:create_message) do |arg|
    @message_submitted = arg
    true
  end
  fill_in 'message', with: 'my message'
  click_on 'submit'
end

Then(/^I should see message submitted$/) do
  page.should have_content 'message submitted'
end

Then(/^the message should be created at ThirdParty$/) do
  @message_submitted.should include 'my message'
end


#8 stevieing

stevieing

    Dispatcher

  • Members
  • 40 posts

Posted 06 November 2013 - 12:05 PM

There is no need to stub the method. You would stub the request to the third party because that is not possible to recreate in your test and return the response you expect. You would usually stub at the lowest level possible

 

i.e ThirdParty.stub(:send_request).and_return(:standard_response).

 

This could be managed via a tag in your cucumber feature.

 

so for example your feature would read:

 

@thirdparty_request

Given I am on the contact page

When I submit the message

Then I should see message submitted

And the message should be created at ThirdParty

 

Then in your step definitions:

 

Before('@thirdparty_request') do

 ThirdParty.stub(:send_request).and_return(:standard_response)

end

 

You could then change back your step to:

 

When(/^I submit a message$/) do
  fill_in 'message', with: 'my message'
  click_on 'submit'
end

 

Using a tag has the advantage that it can be reused wherever you make your third party request.

 

Hope that makes sense.

 

Steve.







Also tagged with one or more of these keywords: cucumber

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users