One of the strengths of an algorithm like BCrypt for storing encrypted passwords lies in the fact that it is relatively slow and can readily be made slower. This makes brute force attacks time-prohibitive. The bcrypt-ruby gem gives you easy access to this cost factor to slow down encryption as needed. The default cost is 10. This provides good security for encrypting user passwords, but if your Rails application depends on users being signed in, you may find this default cost has a substantial impact on the performance of your integration tests. Both Devise and Authlogic provide hooks into their BCrypt interface which allows you to easily change the cost, and this can come in very handy during testing.

# Place in test_helper.rb or spec_helper.rb
Devise.setup do |config|
  config.stretches = 1
end
# Place in test_helper.rb or spec_helper.rb
AuthLogic::CryptoProviders::BCrypt.cost = 1

If you’re authentication needs are simple and you have instead opted to use Rails’ SecurePassword, you will find that, at least as of Rails 3.2.9, there is no obvious way to lower the cost factor. However, if you’re willing to live with a little monkey patching, you can achieve the same results.

# Place in test_helper.rb, spec_helper.rb or spec/support/...
require 'bcrypt'

class BCrypt::Password
  class << self
    method = instance_method(:create)
    define_method :create do |arg, options = {cost: 1}|
      method.bind(self).call(arg, options)
    end
  end
end

Is it worth doing? Here are the before and after measurements on an application I’m currently working on. This particular application is an internal application for a client. There are no guest features, which means every single feature depends on a user having first signed in.

Before…

$ SPEC_OPTS="--seed 48858" bundle exec rspec ./spec/features
..................................................................................................................

Finished in 42.67 seconds
114 examples, 0 failures

Randomized with seed 48858

…and after…

$ SPEC_OPTS="--seed 48858" bundle exec rspec ./spec/features
..................................................................................................................

Finished in 27.36 seconds
114 examples, 0 failures

Randomized with seed 48858

Before the change the integration tests run in 43 seconds; after the change the tests run in 27 seconds. That’s roughly a 37 percent speed-up. I’ll take it.