Testando datas no Ruby
Leia em 1 minuto
Estou reescrevendo o Spesa e, obviamente, ele exige uma série de cálculos com datas devido aos agendamentos. Na versão anterior, a maioria destes cálculos era feita em consultas SQL, trazendo uma complexidade um tanto quanto desnecessária, já que muito da lógica fica no banco de dados, incluindo algumas Stored Procedures.
Na nova versão toda esta lógica foi trazida para o Ruby, o que facilitou o desenvolvimento. Mas nem tudo foi fácil. Os testes exigiram um pouco de pesquisa — não mais que alguns minutos — já que testar datas é sempre um pouco mais complicado. A dificuldade está em manter a consistência, já que o resultado irá variar dependendo do dia que você executar os testes.
Devido a possibilidade de sobrecarga de métodos que o Ruby oferece, é simples e ao mesmo tempo elegante. Utilizando o código abaixo é possível forçar o método Time.now
para sempre retornar uma data específica.
class Time
class << self
# Time we might be behaving as
attr_reader :mock_time
# Set new time to pretend we are.
def mock_time=(new_now)
@mock_time = new_now
end
# now() with possible augmentation
def now_with_mock_time
mock_time || now_without_mock_time
end
alias_method_chain :now, :mock_time
end
end
Adicione o código acima ao seu helper de testes, que no meu caso é "spec/spec_helper.rb", pois estou usando RSpec. Para usá-lo, basta definir uma data como sendo a atual. No exemplo abaixo estou definindo a data atual como sendo "28/02/2007".
it "should mock today method" do
mocked_today = Time.gm(2007, 2, 28)
Time.mock_time = mocked_today
mydate = Date.today
mydate.should eql(mocked_today.to_date)
end
Vi essa dica no Ruby Forum e com certeza vale o bookmark.
Update: Seguindo a dica do Tapajós, você pode usar o Mocka, mas de uma maneira diferente da explicada por ele:
Time.stubs(:now).returns(Time.gm(2008, 2, 1))
Update 2: Mais simples ainda e usando apenas o próprio RSpec:
Time.stub!(:now).and_return(Time.gm(2008, 2, 1))