2010-08-11 6 views
14

estoy tomando una puñalada en la creación de pruebas unitarias para algunas clases de utilidad en un proyecto que estoy trabajando, y una de las clases (contiene información de licencia) tiene un método eso hace algo de determinación basado en la hora actual.Manejo de pruebas unitarias con una condición en la hora actual

es decir, la licencia contiene una fecha de caducidad, y la cadena de la licencia valida esa fecha, pero la lógica real para ver si la licencia expiró se basa en la hora actual.

public boolean isValid() 
{ 
    return isLicenseStringValid() && !isExpired(); 
} 

public boolean isExpired() 
{ 
    Date expiry = getExpiryDate(); 
    if(expiry == null) { 
     return false; 
    } 

    Date now = new Date(); 

    return now.after(expiry); 
} 

Por lo tanto, no estoy seguro de qué hacer, ya que el 'new Date()' que no es un criterio estático.

  1. ¿Debo no se molestan en comprobar 'isValid', y justo prueba 'isLicenseStringValid()' y el 'getExpiryDate()' función por separado?
  2. ¿Acabo de utilizar una clave de licencia en la prueba con una larga expiración loca de modo que habré cambiado de trabajo antes de que caduque?
  3. ¿Trato de burlarse out 'new Date()' a algún método 'getCurrentTime()' tal que puedo fingir que hora es ahora?

¿Qué hacen normalmente otros con las pruebas que dependen del tiempo?

+0

Por cierto, veo un problema en su código que no sea la lógica fecha: si (caducidad == null) {return false ; } No creo que deba devolver 'false' en el método' isExpired() 'si la fecha de caducidad es nula. Para obtener más información, lea: https://www.owasp.org/index.php/Fail_securely – Garbage

+0

Es un objeto de licencia que tiene dos modos posibles: 1. perpetuo sin fecha de caducidad (de ahí lo anterior) 2. temporal con una fecha de caducidad por lo tanto, es correcto que, si no hay una fecha de vencimiento establecida, no está vencida. –

Respuesta

23

Definitivamente burlan a cabo new Date().

Cree una interfaz Clock con un método getCurrentTime() o algo similar. De esta forma, puede tener un FakeClock para probar y un SystemClock que usa System.currentTimeMillis() o lo que sea.

He hecho esto varias veces - que ha funcionado muy bien. También es lógico: efectivamente necesita un "servicio horario actual", por lo que debe ser inyectado como cualquier otra dependencia.

+0

Gracias, se siente un poco raro usar DI para cosas que se sienten como parte del lenguaje en sí, pero parece que esto funcionará. –

5

lo general inyectar un proveedor de fecha en el código de prueba. Esto también ayuda si necesita cambiar las convenciones o "corregir" el código de prueba de tiempo.

2

Use la inyección de dependencia e inyecte un TimeProvider que proporciona un método getExpiryDate().

1

Los tres enfoques son posibles:

  1. no hacer la prueba: el camino del hombre perezoso
  2. utilizar una licencia que no expirará durante siglos hasta que haya dejado el trabajo: cubrir mi camino culo
  3. utilizar una maqueta para la fecha actual, como por ejemplo un TimeProvider: la forma perfeccionista

me gustaría ir para un comprimise: me gustaría añadir la fecha actual como un parámetro para el método isExpired y el isValid método. Para su código de producción en vivo, agregue una anulación simple no-arg isValid() que llame al isValid(new Date()). Su código de prueba usa la versión que toma la fecha actual como parámetro.

+0

Esta opción me gusta más. Si el lenguaje admite argumentos predeterminados, lo hace un poco más fácil. – elias

2

Si siente que la abstracción TimeProvider/Reloj es demasiado al agua perfeccionista (que puede muy bien ser el caso), tenga en cuenta esto en su lugar

Haga getCurrentType protegido virtual, a continuación, crear una decendant TestingProductionType del ProductionType que contiene el código publicasteEn ese tipo, anula el método getCurrentType() para devolver algún resultado determinista. En su prueba de unidad, cree una instancia de este TestingProductionType en su lugar.

Viola, la dependencia de la hora actual ahora se elimina de las pruebas de su unidad. El único código de producción que ahora no está probado en unidades es un método con una sola línea que devuelve una nueva Fecha(). Podría vivir con eso.