Integration Tests with Minitest
Over the course of 2014 I focused a great deal of my energy at work coming up with a decent test suite for our application. Our application was developed over the course of late 2012 and most of 2013 but, unfortunately, was done so with only about 5% test coverage.

The lack of a viable test suite cost us. A lot. Between the extra time it took to hunt down, find, and fix regressions and the time we spent redeveloping features, we lost almost 3 months of 2014. 3 months! That’s a lot of lost development time. More often than not, our lost time was over poorly planned features. Without having implemented some form of acceptance testing and general task management, features would get released and, like clockwork, a stakeholder would come in after the fact (i.e., post release) indicating all the items that were missing, wrong, etc. Total PIA.

As such, I made it my mission to start improving our development flow and building out a legitimate test suite. By the end of 2014, I have our coverage up to ~50%, up from 5% in January. The initial work throughout 2014 focused on the application’s models and services (there are a lot of services). Next up, in 2015, is fleshing out a series of integration (read: feature) tests … my achilles heel, if you will.

Integration Tests are Hard
Well, they are for me anyway. Models, controllers, helpers and services are all fairly easy to test … or, at the least, fairly easy to figure out what and how to test. Because integration (feature) tests deal with multiple controllers and actions, they’re actually kind of hard to learn not only what to write/test but how to write/test.

Slow Down. Back Up. Make it Easier.
Trying to start integration testing with a massive application just wasn’t working for me. So, like any good Ruby|Rails developer, I decided to create a new app - one that I’ve been meaning to build for a year - a team management application for youth basketball teams, with the uninspired name of basketball team manager. FWIW, I’m the girls’ high school basketball coach here in Ouray, hence the desire and need for this app!

The intent of the app, the subject of a forthcoming, insanely exciting blog post, is pretty simple: providing coaches the ability to schedule, run and manage a practice.

Two Really Simple Integration Tests
To get started, I created two simple integration tests: one for user authentication and another for editing one’s profile. Pretty simple and straightforward features, if not overly simplified. However, all did not go so easily when it came time to run the test for editing one’s profile.

user_authentication_test.rb

require 'test_helper'

class UserAuthenticationTest < ActionDispatch::IntegrationTest
  # the original iterations of this test did not have the setup or teardown methods as you see below
  def setup
    $team = teams(:ouray)
  end

  def teardown
    logout
  end

  test 'visit home page and login' do
    visit root_path

    click_link 'Sign in'

    assert_equal sign_in_path, current_path

    fill_in 'Email', with: users(:coach).email
    fill_in 'Password', with: 'password'
    click_button 'Sign in'

    page.has_selector?('h3>u')
    page.has_content?('Your Team')
  end

end

edit_profile_test.rb

require 'test_helper'

class EditProfileTest < ActionDispatch::IntegrationTest
  # the original iterations of this test did not have the setup or teardown methods as you see below
  # rarther, logins were handled initially in the body of the test method itself.
  def setup
    login
  end

  def teardown
    logout
  end

  test 'edit a user account details' do
    @fan = users(:fan)
    visit edit_user_path(@fan, as: @user.id)

    fill_in 'Last name', with: 'Coacharino'
    fill_in 'First name', with: 'Craig'
    click_button 'Update User'

    @fan.reload

    assert_equal 'craig coacharino', @fan.name.downcase
  end
end

The ‘Issue’ with Capybara, Minitest and Clearance
The user authentication test worked right out of the box. But no matter what I did, the edit profile test failed. The long and short of it was that sessions were not being maintained throughout the test and when it hit the update method of the appropriate controller, it (read: Clearance) would redirect the user to the homepage and rollback DB changes, thus causing the test to fail.

After a decent amount of banging my head against my desk and four mild concussions later, I figured out how to make Capybara, Clearance and Minitest play nice regarding sessions, etc. The following updates to my test_helper.rb saved the day.

test_helper.rb

class ActionDispatch::IntegrationTest
  include Capybara::DSL
  include Capybara::Assertions

  def login(role='coach')
    @user = case role
        when 'coach'
          users(:coach)
        when 'fan'
          users(:fan)
        when 'player'
          users(:player)
        when 'captain'
          users(:captain)
    end

    visit root_path

    click_link 'Sign in'

    fill_in 'Email', with: @user.email
    fill_in 'Password', with: 'password'
    click_button 'Sign in'
  end

  def logout
    click_link 'Sign out'
  end
end

tl;dr
When I tried to handle the logins within my integration tests, it never seemed to hold the session data and my tests failed time and again (I’m sure I was making some idiotic mistake that I’ve still yet to figure out). But, ultimately, Ruby’s open classes saved the day … and they kick ass. All I needed to do was to extend ActionDispath::IntegrationTest to handle the login and logout methods and my edit profile test passed swimmingly.

Now let’s get testing!