ruby-on-railsrspeccapybarastubwebmock

Am I stubbing data correctly?


Imagine I have an app that uses Twitter API. In my app I only have a textarea and a button in which if I submit the form it will tweet to my account.

In my app I have the following routes:

resources :tweets, :only => [:index, :new, :create]

In my controller I have:

class TweetsController < ApplicationController
  def index
    @tweets = [JSON RESPONSE FROM API (LIST OF TWEETS)]
  end

  def create
    @tweet = [POST REQUEST TO CREATE A TWEET]

    flash[:notice] = 'Tweet has been created successfully.'

    redirect_to tweets_path
  end
end

In my view file:

<ul>
 <% @tweets.each do |tweet| %>
  <li><%= tweet %></li>
 <% end %>
</ul>

Now this works just fine. But when testing the app I am using Rspec and Capybara.

In my test file I have this code:

require 'rails_helper'

feature 'User creates' do
  scenario 'a tweet' do
    visit new_tweet_path

    fill_in 'Tweet', :with => 'My Example Tweet'
    click_on 'Submit'

    expect(page).to have_content 'My Example Tweet'
    expect(page).to have_content 'Tweet has been created successfully.'
  end
end

This test file succeeds but the problem is that it 'creates' real data. I don't want to populate my account with dummy data whenever I run the test.

The test above returns page.body as an HTML document, it renders the view above. So the success of the test above returns something like this:

Tweet has been created successfully.
<ul>
  <li>Tweet</li>
  <li>My other tweet</li>
  <li>My Example Tweet</li>
</ul>

As you can see, this is because the create redirects to index which fetches all tweets and iterates it. But this call the API everytime I run the test.

That's when I discovered stubbing data.

I use Puffing Billy to create a stub on my tests.

In my tests I use it like this:

require 'rails_helper'

feature 'User creates' do
  scenario 'a tweet' do
    proxy.stub(tweets_url, :method => :post).and_return(
      :json => {
        "status"=>"OK",
        "message"=>"Tweet has been created successfully.",
        "data"=>{
          "tweet"=>"My Example Tweet",
        }
      }
    )

    visit new_tweet_path

    fill_in 'Tweet', :with => 'My Example Tweet'
    click_on 'Submit'

    expect(page).to have_content 'My Example Tweet'
    expect(page).to have_content 'Tweet has been created successfully.'
  end
end

Basically, I am stubbing data on my create method. And this test case succeeds but the problem is this is not how my apps works.

The normal process is that it will redirect me to index to check the page if has the contents.

But after stubbing it will just simply return me JSON and not the HTML document.

Is this how stubbing is done, or I am doing something wrong?


Solution

  • Puffing Billy is a programmable proxy which can be used to stub requests from the browser. In your case the requests you are looking to stub are coming from your app instead of the browser. Generally requests from your app would be stubbed using something like WebMock or by writing a fake service. The article - https://robots.thoughtbot.com/how-to-stub-external-services-in-tests - has a good summary of stubbing requests from inside your app.

    Another potential option is if whatever library you're using to communicate with twitter provides it's own test mode.