2011-05-25 10 views
8

Estoy escribiendo un código que hace cálculos de fecha y hora contra la hora actual. En el tiempo Joda, se accede a través de un constructor (Java), ya que es un objeto inmutable. Necesito poder simular para que new DateTime() devuelva un instante constante específico para que pueda hacer afirmaciones de prueba razonables, pero deje todos los demás métodos DateTime solo.En Grails, ¿hay alguna manera de burlarse de la hora actual usando Joda time?

Esto está demostrando ser desagradable. Grails mockFor(DateTime, true) no me dejará simular un constructor de Java, sin embargo, no existe una forma obvia o legible que no sea de constructor de obtener el tiempo en tiempo Joda.

Las únicas opciones disponibles parecen implicar técnicas de JVM de bajo nivel como JMockit o EasyMock 3 burla de clase, que son un dolor de Grails. ¿Hay una manera simple/directa de lograr esto?

Respuesta

5

Terminamos creando dateService con now() método. En las pruebas de unidad nos burlamos con

domainInstance.dateService = [ now: { currentTime } ] as DateService 

donde currentTime es un campo de clase de prueba de unidad. Esto impone la dependencia de todo el mundo en dateService (nuestra única dependencia casi-global), y por src clases uno tiene que pasar por la mano.

Las pruebas unitarias, otoh, se ven bastante clara con él.

+0

Gran respuesta. Tenía la esperanza de evitar diseñar el sistema de otra forma para hacer posible esta prueba, pero aprendí mucho sobre lo doloroso que puede ser burlarse de los constructores. –

+0

Gracias. Intento evitar la invocación directa del constructor: viola el "código para la interfaz", la instancia creada no se puede externalizar como en las pruebas, y algunas veces lleva a 'Blobs de construcción'. Entonces se redujo a una forma de inyección de dependencia. –

2

usted podría utilizar buenos principios OO pasado de moda, por ejemplo,

interface TimeService { 
    DateTime getCurrentTime() 

    // other time-related methods 
    } 

    class JodaTimeService implements TimeService { 
    DateTime getCurrentTime() { 
     new DateTime() 
    } 
    } 

    class MockTimeService implements TimeService { 
    DateTime getCurrentTime() { 
     // return a fixed point in time 
    } 
    } 

El código debe obtener una referencia a una implementación de TimeService a través de la inyección de dependencia. En resources.groovy utilizar el MockTimeService solamente al ejecutar las pruebas

import grails.util.Environment 

beans = {  
    if (Environment.current == Environment.TEST) { 
     timeService(MockTimeService) 

    } else { 
     timeService(JodaTimeService) 
    } 
} 
+0

Independientemente del mismo enfoque que el anterior, muchas gracias, y una buena solución trabajada en profundidad. Y un agradecimiento adicional por las sugerencias sobre el uso del entorno de prueba para cambiar. –

18

sé esto como ya ha sido aceptado, pero con Joda-tiempo se puede congelar y configurarlo para ser lo que quiera. De modo que puede congelar el tiempo, adelantar el tiempo, retroceder en el tiempo. Siempre que use Joda de manera consistente, sus objetos aparecerán "ahora" como el tiempo que haya establecido.

// Stop time (and set a particular point in time): 
DateTimeUtils.setCurrentMillisFixed(whenever); 

// Advance time by the offset: 
DateTimeUtils.setCurrentMillisOffset(offsetFromCurrent); 

// Restore time (you could do this in an @After method) 
DateTimeUtils.setCurrentMillisSystem(); 
+0

Oooh, bien, había estado esperando algo como esto. Esto hará que las pruebas sean mucho más fáciles. Gran consejo !! –

+0

Ahora me siento estúpido, porque estamos en Joda. Es una mejor manera. Bien, aprendí algo. –

Cuestiones relacionadas