Creating a User

To get our first step to pass, we need to be able to create a user in our system. We could do that by walking around the UI, filling in the user registration forms and clicking buttons, but actually that’s not the point of this feature. Our goal is to build the page where you can see a user’s messages so we don’t need to worry about all that user registration stuff.

Let’s imagine we have a fast-forward button, and we skip past all the user registration to the point where the user has registered. What state is the system in now?

Well, we don’t know for sure because we haven’t built those screens yet, but it seems safe to assume that there would be a new row in the users table in our database. To get the system into that state, we can use the Rails models to add a User record to the system, just as though they had registered. A great library to help us work with ActiveRecord, the library Rails uses to talk to the database, is called FactoryGirl.[57] Let’s add her to the test group in our Gemfile:

 group ​:test​ ​do
  gem ​'cucumber-rails'​, ​'1.4.5'​, ​require: ​​false
  gem ​'cucumber'​, ​'3.0.0.pre.1'
  gem ​'rspec-rails'​, ​'3.5.2'
  gem ​'database_cleaner'​, ​'1.5.3'
  gem ​'factory_girl'​, ​'4.7.0'
 end

Now we can implement the step definition for our first step. We’ll create it in a file called step_definitions/user_steps.rb:

 Given(​/^there is a User$/​) ​do
  FactoryGirl.create(​:user​)
 end

We’re calling FactoryGirl’s special helper method Factory, telling it to create us a standard instance of the User model. If you run the feature now, you should see the following error:

 Feature: See Messages
 
  Scenario: See another user's messages
  Given there is a User
  uninitialized constant User (NameError)
  ./features/step_definitions/user_steps.rb:2
  features/see_messages.feature:3
  And the User has posted the message "this is my message"
  Undefined step: "the User has posted the message "this is my message""
  (Cucumber::Undefined)
  features/see_messages.feature:4
  When I visit the page for the User
  Undefined step: "I visit the page for the User" (Cucumber::Undefined)
  features/see_messages.feature:5
  Then I should see "this is my message"
  Undefined step: "I should see "this is my message"" (Cucumber::Undefined)
  features/see_messages.feature:6
 
 Failing Scenarios:
 cucumber features/see_messages.feature:2
 
 1 scenario (1 failed)
 4 steps (1 failed, 3 undefined)
 0m0.107s
 
 You can implement step definitions for undefined steps with these snippets:
 
 Given(/^the User has posted the message "([^"]*)"$/) do |arg1|
  pending # Write code here that turns the phrase above into concrete actions
 end
 
 When(/^I visit the page for the User$/) do
  pending # Write code here that turns the phrase above into concrete actions
 end
 
 Then(/^I should see "([^"]*)"$/) do |arg1|
  pending # Write code here that turns the phrase above into concrete actions
 end

Why? Well, we need to tell FactoryGirl how to create a user. Create a file called features/support/factories.rb, and give it some very basic sample data:

 require ​'factory_girl'
 
 FactoryGirl.define ​do
  factory ​:user​ ​do​ |f|
  f.username ​'testuser'
 end
 end
Joe asks:
Joe asks:
Why Do I Need FactoryGirl When I Can Just Create Records with ActiveRecord Directly?

It’s really easy to create rows in your database just using ActiveRecord directly. For our User class, we could use this code:

 User.create! ​:username​ => ​'testuser'

The problem with doing this is that as the shape of your User evolves, more attributes are added, and validation rules are implemented, the hash of data that you need to pass will get longer and longer. Pretty soon it could easily look like this:

 User.create! ​:username​ => ​'testuser'​,
 :password​ => ​'password'​,
 :password_confirmation​ => ​'password'​,
 :email​ => ​'[email protected]'​,
 :first_name​ => ​'Test'​,
 :last_name​ => ​'User'

Now you have a bunch of problems. First, you have a duplication problem: each time you add a new mandatory field to User, you have to hunt for every place where you’ve called User.create! and add the new field to the hash, along with a sample value. Second, you have an incidental detail problem. The precise attributes of the user are totally irrelevant to our See messages scenario, yet there’s all this noise in the step definition where we need to create a user. That’s distracting for anyone who has to come along and modify this code later, especially in another scenario where one of those attributes is actually relevant to what’s being tested.

One solution, which is still baked into Rails at the time of writing, is to use fixtures. We explain the problems with using fixtures in Chapter 6, When Cucumbers Go Bad.

FactoryGirl is an implementation of the Test Data Builder pattern as first described by Nat Pryce.[58] It allows you to configure what a standard instance of any ActiveRecord database object should look like in a central place so that your test code is clutter-free. Remember that you can use ActiveRecord and FactoryGirl to set up data in any SQL database, whether or not the application you’re testing is written in Ruby.

We haven’t given much thought to the attributes for our user yet. That’s OK, because Rails will let us change the columns in the users table easily using migrations, and our Cucumber features will always tell us whether things are still working. Right now we can concentrate on doing something simple and getting it to work.

If we run the features again, we should have made some progress:

 Feature: See Messages
 
  Scenario: See another user's messages
  Given there is a User
  And the User has posted the message "this is my message"
  Undefined step: "the User has posted the message "this is my message""
  (Cucumber::Undefined)
  features/see_messages.feature:4
  When I visit the page for the User
  Undefined step: "I visit the page for the User" (Cucumber::Undefined)
  features/see_messages.feature:5
  Then I should see "this is my message"
  Undefined step: "I should see "this is my message"" (Cucumber::Undefined)
  features/see_messages.feature:6
 
 1 scenario (1 undefined)
 4 steps (3 undefined, 1 passed)
 0m0.116s
 
 You can implement step definitions for undefined steps with these snippets:
 
 Given(/^the User has posted the message "([^"]*)"$/) do |arg1|
  pending # Write code here that turns the phrase above into concrete actions
 end
 
 When(/^I visit the page for the User$/) do
  pending # Write code here that turns the phrase above into concrete actions
 end
 
 Then(/^I should see "([^"]*)"$/) do |arg1|
  pending # Write code here that turns the phrase above into concrete actions
 end

Ah yes, a new error. So, working our way from the outside-in, we’ve hit the point where we need to actually create the User model. Don’t worry about the undefined steps for now—we’ll get to those later. We know that the user needs to have a username, so let’s use the Rails model generator to create our very simple User model:

 $ ​​bin/rails​​ ​​generate​​ ​​model​​ ​​User​​ ​​username:string

If we run the features now, we’ll see that—hooray!—FactoryGirl can now find the User model, but there’s no users table in our test database. Let’s fix that:

 $ ​​bin/rake​​ ​​db:migrate​​ ​​db:test:prepare

Run the features now, and you should see that the first step has passed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.144.65