2009-04-03 10 views
5

¿Cuál es la mejor manera de escribir la prueba de unidad para el código que obtiene la hora actual? Por ejemplo, algunos objetos pueden crearse solo en días hábiles, otros objetos tienen en cuenta la hora actual al verificar permisos para ejecutar algunas acciones, etc.Código de prueba de unidad que obtiene la hora actual

Supongo que debería simular Date.today y Time.now. ¿Es este el enfoque correcto?

Actualización: Ambas soluciones (a) Time.is y (b) Time.stubs (: now) .returns (t) work. (a) es un enfoque muy bueno pero (b) la solución será más consistente con otro código de prueba.

En este question un autor pide una solución general. Para Ruby, en mi opción, las dos soluciones anteriores son simpler y, por lo tanto, es mejor que extraer el código que obtiene la fecha/hora actual.

BTW Recomiendo usar Chronic para obtener el tiempo requerido, p.

require 'Chronic'  
mon = Chronic.parse("next week monday") 
Time.stubs(:now).returns(mon) 
+1

¿Por qué es esta comunidad wiki? – Elie

+0

¿Por qué no puede ser wiki de la comunidad? –

+1

Puede, pero con la mayoría de las preguntas de programación específicas, no está hecho para que la gente pueda obtener reputación por ello. No tengo una respuesta, por lo que no me afecta, pero tenía curiosidad. – Elie

Respuesta

3

que imita Time.now o Date.today parece bastante sencillo, sería algo como:

require 'rubygems' 
require 'test/unit' 
require 'mocha' 

class MyClass 

    def foo 
    Time.now 
    end 

end 

class MyTest < Test::Unit::TestCase 

    def test_foo 
    assert true 
    t = Time.now 
    Time.expects(:now).returns(t) 
    assert_equal t, MyClass.new.foo 
    end 

end 
3

pasar una ITimeProvider (por ejemplo) la clase a su rutina de usar para obtener el tiempo, entonces usted puede burlarse de él y utilizar el objeto de burla para siempre le dará un tiempo consistente para la rutina de usar.

3

Desde mi punto de vista, supongo que el mejor enfoque para esto sería no permitir que su objeto obtenga el tiempo. En otras palabras, pase la fecha/hora al método que se llame al objeto que está usando las construcciones de tiempo incorporadas actualmente. Dependiendo de sus circunstancias, esto podría ser una solución mucho más simple que imitar a Date.today y Time.now, como sugiere.

Editar: Digo esto en agudo contraste con la sugerencia de tener una interfaz ITimeProvider que se transfiere como una dependencia ... eso es exagerado, en mi opinión.

0

Crear un objeto de ITimeProvider como una dependencia es mejor que pasar el tiempo porque se ajusta al principio de No repetir usted mismo.

En algún lugar de su código de producción, algo tiene que obtener la hora actual. Puede tomar el código de generación de fecha fuera de los límites de su cobertura de prueba o puede tener un solo objeto fácil de probar que puede estar en cualquier otro lugar.

+0

Normalmente, obtener la hora actual es una expresión única, p. nueva fecha() en Java. Resumir eso en una interfaz es una sobreingeniería absurda. Probablemente terminarás repitiéndote incluso más que antes. –

+0

Ciertamente no es para todos los proyectos. Solo consideraría hacer algo como esto si dependiera en gran medida de lo que era el momento. –

+0

¿Está diciendo que hay una violación DRY porque tanto el código de producción como el código de prueba generan el tiempo? Si es así, ¿cómo lo reemplaza con un simulacro de ayuda? Además, ¿falta una palabra en "o puede tener un solo objeto fácil de probar que puede estar en cualquier otro lugar"? –

6

El siguiente es de Jay Field's Thoughts. Le permite redefinir Time.now durante la duración de un bloque.

require 'time' 

class Time 
    def self.metaclass 
    class << self; self; end 
    end 

    def self.is(point_in_time) 
    new_time = case point_in_time 
     when String then Time.parse(point_in_time) 
     when Time then point_in_time 
     else raise ArgumentError.new("argument should be a string or time instance") 
    end 
    class << self 
     alias old_now now 
    end 
    metaclass.class_eval do 
     define_method :now do 
     new_time 
     end 
    end 
    yield 
    class << self 
     alias now old_now 
     undef old_now 
    end 
    end 
end 

Time.is(Time.now) do 
    Time.now # => Tue Nov 13 19:31:46 -0500 2007 
    sleep 2 
    Time.now # => Tue Nov 13 19:31:46 -0500 2007 
end 

Time.is("10/05/2006") do 
    Time.now # => Thu Oct 05 00:00:00 -0400 2006 
    sleep 2 
    Time.now # => Thu Oct 05 00:00:00 -0400 2006 
end 
Cuestiones relacionadas