Use o método save! ao escrever seus testes


Leia em menos de um minuto

Toda vez que você estiver escrevendo um teste — seja ele qual for — e tiver que chamar o método save, opte pelo método save!. A diferença entre eles é que o primeiro retorna true ou false em caso de sucesso ou falha, respectivamente. Já o segundo, irá disparar a exceção ActiveRecord::RecordInvalid, caso o modelo seja inválido em relação às suas regras de validação.

Aplicado aos testes, a vantagem do método save! está na dependência de alguma alteração do modelo para testar uma outra situação. Imagine o seguinte modelo:

class User < ActiveRecord::Base
  validates_length_of :password,
    :minimum => 4,
    :message => 'A senha deve ter no mínimo 4 caracteres'

  attr_accessor :password
end

Já o teste irá validar se um usuário pode se logar com um cookie expirado.

def test_should_fail_expired_cookie_login
  user = users(:quentin)
  user.remember_me
  user.remember_token_expires_at = 5.minutes.ago
  user.save

  @request.cookies["auth_token"] = cookie_for(:quentin)
  get :index
  assert !@controller.send(:logged_in?)
end

Ao executá-lo, ele falharia porque o atributo password não foi definido e o método validates_length_of invalidaria nosso modelo, só que você não iria ter nenhuma indicação de que esse foi o motivo. Neste caso, se você trocar a linha user.save por user.save!, uma exceção seria disparada, indicando qual validação não passou. No modelo você poderia utilizar o seguinte código para validar o modelo:

class User < ActiveRecord::Base
  validates_length_of :password,
    :minimum => 4,
    :message => 'A senha deve ter no mínimo 4 caracteres',
    :if => :require_password?

  attr_accessor :password

  private
    def require_password?
      !password.blank?
    end
end