views:

145

answers:

4

I am trying to do some Cucumber testing like the following:

Given I am logged in as admin
When I go to the article page
Then I should see "Edit Article"
And I should see "Article Title"

where the path to the article page is "articles/1" or some known id.The problem is that when I insert my data using my step definition

Article.create(:name => "Article Title")

I can't know ahead of time what the id will be when the record is inserted.

Essentially, I either need

a) to be able to insert predictable ids. I've tried the method mentioned in the answer of this question but it doesn't seem to work for me - it always inserts a different id.

or

b) write my cucumber steps in such a way that I can pass in a parameter for my Article id

All Cucumber tutorials I've seen sort of gloss over this type of scenario - it's always going to the list of all Articles or whatever, never a specific detail page.

Any help would be appreciated. Thanks!

+1  A: 

There are two ways to create predictable ID values. The first is to manually set the ID on create:

model = Model.new(options)
model.id = DESIRED_ID
model.save

The catch here is that options passed to either new, create, or update_attributes will not affect the id value which is why the call to model.id is, unfortunately, required.

An alternative is to reset the whole table before running your tests. This can be altered to account for fixtures if required. For example:

class Model < ActiveRecord::Base
  def self.reset!
    connection.execute("DELETE FROM #{table_name}")
    connection.execute("ALTER TABLE #{table_name} AUTO_INCREMENT=1")
  end
end

This will set the ID of the first row inserted to be a predictable 1.

tadman
+4  A: 

How about navigating to the article page in the way a user would do it? Your step

When I go to the article page

could be changed to

When I go to the page for the "Article Title" article

and your step definition goes to an article overview, finds a link with "Article Title" and navigates to the page that way.

You get more test coverage, and don't have to worry about IDs.

Magnar
This doesn't quite hit at the heart of what I am trying to test here (my example is somewhat simplified) although I may use this elsewhere in testing my app. Thanks.
Doug R
This is what the tutorials suggest - you *could* use features (I think) but that would make it harder to see what's going on
Ghoti
+1  A: 

How about making "Go to the Article Page" go to "/articles/#{Article.first.id}"

Michael Sofaer
A: 

This is what I use:

# feature
Scenario: creator archives fragment
  When fragment 1 exists
  And I am the fragment owner
  And I am on fragment 1

#steps
def create_fragment(attribs)
  force_id = attribs[:force_id]
  attribs.delete(:force_id) if force_id
  fragment = Fragment.create!({ :owner_id => @current_user.id, :originator_id => @current_user.id}.merge(attribs))
  if force_id
    fragment.id = force_id.to_i
    fragment.save!
  end
  fragment
end

When /^fragment (.*) exists$/ do |frag|
  @fragment = Fragment.find_by_id(frag)
  @fragment.destroy if @fragment
  @fragment = create_fragment(:force_id => frag.to_i,:description => "test fragment #{frag}",:narrative => "narrative for fragment #{frag}")
end


# paths.rb
when /fragment (.*)/
fragment_path($1)

Have fun.

Ghoti