Maybe you are in this transition to become a professional programmer (congrats!!) and you have seen that if you want to be “a professional programmer” you have to use TDD and test all your code.

That is not always true, there are some teams with awesome programers that don’t use TDD or don’t test all their code. Actually I think not even Uncle Bob (the clean coder) has tests for all his code. He always says that he does not test view code (like html and css).

But I am with you. I think that you need to write tests! … but your problem is that although you want to make test, you have no clue of how to start.

You are just stuck after you do:

rails g rspec:feature visitor_sees_homepage

Don’t worry, is not as easy as typing something in the terminal. But is not that hard also! The secret is to think like if you were writing a specification.

For example, if you are writing a TweetFeed, instead of thinking that you will need a Tweet model that has a message, user_id, created_at, etc. You will think how your program will serve the user. After all the software that you are writing is for someone.

So thinking in your TweetFeed, let’s start by writing some things that it has to do to serve the user, for example:

  • It should show a list of tweets
  • It should show the tweets ordered by date, with the last tweet at the top.
  • It should show the tweets of the people you are following
  • Each tweet should show the name of the author
  • Each tweet should show the date it was created
  • Each tweet should show the message the author wrote
  • Each tweet should show the number of retweets
  • etc.

… as you can see, is not that far from what you were thinking, but is showing in an other point of view.

You can test this behaviour at different levels, but maybe the easiest way to visualise it, is using capybara, because your code actually represents what a user is doing in a web browser.

The problem is that this kind of tests are very complex, because you have to know a lot of things and are very fragile because it takes in account a lot of implementation details, like how you display the data, or if you are using a button instead of a link.

But this kind of tests is what you are using now, and I don’t want to confuse you more.

So, let’s define the “feature” test…

Always start describing what a user will do/see without thinking how you will accomplish it, for example:

feature "User sees tweet feed" do
  scenario "in her homepage" do
    michel_jordan = create :user, name: "Michael Jordan"
    madonna = create :user, name: "Madonna"
    user = given_a_user_following(michel_jordan, madonna)

    first_tweet = create :tweet, author: michel_jordan, created_at: "2015-04-04", message: "I'am back", retweets: 100
    second_tweet = create :tweet, author: madonna, created_at: "2015-04-04", message: "My new song", retweets: 200

    visit root_path
    expect_page_to_have_ordered_tweets(second_tweet, first_tweet)
    expect_page_to_have_tweet_with("Michael Jordan", "2015-04-04", "I'am back", "100 retweets")
    expect_page_to_have_tweet_with("Madonna", "2015-04-04", "My new song", "200 retweets")
  end
end

Maybe you will need some practice to think this way, but as you can see we are trying to think very little on the mechanics of how you are going to store/fetch the information. You are now concerned on what the user should see.

After you have defined this structure, is easier to think in how you are going to actually implement those expectations. One way could be:

feature "User sees tweet feed" do
  scenario "in her homepage" do
    michel_jordan = create :user, name: "Michael Jordan"
    madonna = create :user, name: "Madonna"
    user = given_a_user_following(michel_jordan, madonna)

    first_tweet = create :tweet, author: michel_jordan, created_at: "2015-04-04", message: "I'am back", retweets: 100
    second_tweet = create :tweet, author: madonna, created_at: "2015-04-04", message: "My new song", retweets: 200

    visit root_path
    expect_page_to_have_ordered_tweets(second_tweet, first_tweet)
    expect_page_to_have_tweet_with("Michael Jordan", "2015-04-04", "I'am back", "100 retweets")
    expect_page_to_have_tweet_with("Madonna", "2015-04-04", "My new song", "200 retweets")
  end

  def given_a_user_following(users)
    # maybe this is not the best way =P
    create :user, following_ids: users.map(&:id)
  end

  def expect_page_to_have_ordered_tweets(first, second)
    expect(all(".tweet").first).to have_content first.id
    expect(all(".tweet").second).to have_content second.id
  end

  def expect_page_to_have_tweet_with(author, date, message, retweets)
    # maybe not the must correct way
    expect(page).to have_content author
    expect(page).to have_content date
    expect(page).to have_content messate
    expect(page).to have_content retweets
  end
end

At this moment you are now interested a little more in the mechanics of how you are actually making the assertions but is easier because you have divided you have already defined what you expect.

This kind of top-down approach helps me a lot to define expectations and be clear about them. I hope this help you start in the world of testing =)