Adding a User Manager to your Feature Tests

In my last post I described how to write declarative step definitions. However, this means our test cases can’t assume it knows who is performing the action because the user can change at any time. We’ll need to introduce a sort of state machine to track the current user and log in as another user when needed.

I’ve written this example feature to purchase a product using a buyer and seller with the buyer performing two steps in a row.

Feature: purchase product

  Scenario: purchase product
    Given seller has created a product
    When buyer purchases the product
    And buyer sends payment
    Then seller should receive money
    And the product shouldn't be listed

When writing our step definitions we will include a capture group to get the username and then pass that to our UserManager class.

Given(/^(.*) has created a product$/) do |username|
  UserManager.change_user(username)
end

When(/^(.*) purchases the product$/) do |username|
  UserManager.change_user(username)
end

When(/^(.*) sends payment$/) do |username|
  UserManager.change_user(username)
end

Then(/^(.*) should receive money$/) do |username|
  UserManager.change_user(username)
end

Then(/^the product shouldn't be listed$/) do
end

Now for the final piece, the UserManager class. This is a very simple class with a single method to update the current_username variable if it is different. When this variable changes it will tell our LoginPage to log us in with the new username.

class LoginPage
  def self.login_as(username)
    # fill in login fields and submit form here
    puts "Logged in as #{username}"
  end
end

class UserManager
  def self.change_user(username)
    return if @current_username == username
    @current_username = username
    LoginPage.login_as(username)
  end
end

As you can see this is a very small change to make and allows our step definitions to simply carry out the instructions from the high level scenario.