2010-02-17 22 views
7

Tengo este método que depende de la fecha actual. Comprueba si hoy es domingo, lunes, martes o miércoles, luego da 5 días de tiempo de entrega para la llegada de los artículos enviados. Si es Thur, Fri o Sat, da 6 días de tiempo de entrega para el fin de semana.Cómo probar la lógica que depende de la fecha actual

private DateTime GetEstimatedArrivalDate() 
{ 
    DateTime estimatedDate; 
    if (DateTime.Now.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = DateTime.Now.Date.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = DateTime.Now.Date.AddDays(5); 
    } 
    return estimatedDate; 
} 

La lógica de estimación real es más compleja. Lo he simplificado para el propósito de esta pregunta. Mi pregunta es ¿cómo puedo escribir una prueba unitaria para algo como esto que depende de la fecha de hoy?

+0

La respuesta es (casi) en la pregunta "¿Cómo escribo una prueba unitaria para algo como esto que depende de la fecha de hoy?" Refactorice el método para usar inyección de dependencia como en la respuesta de Marcos. –

Respuesta

17

que necesita para aprobar la fecha actual como un parámetro:

private DateTime GetEstimatedArrivalDate(DateTime currentDate) 
{ 
    DateTime estimatedDate; 
    if (currentDate.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = currentDate.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = currentDate.AddDays(5); 
    } 
    return estimatedDate; 
} 

En código real se llama así:

DateTime estimatedDate = GetEstimatedArrivalDate(DateTime.Now.Date); 

A continuación, se puede probar la siguiente manera:

DateTime actual = GetEstimatedArrivalDate(new DateTime(2010, 2, 10)); 
DateTime expected = ...; 
// etc... 

Tenga en cuenta que esto también corrige un error potencial en su programa donde la fecha cambia entre llamadas consecutivas a DateTime.Now.

+0

Acabo de publicar la misma respuesta. Me ganaste a la velocidad :) – Romain

+0

arregló el si para ti. –

+1

+1 para la última línea ... –

0

Parece que hay un número limitado de casos en los que puede probarlos de forma explícita. El método depende de la fecha de hoy, pero la salida depende únicamente del día de la semana, y cada fecha tiene un día de la semana.

0

Puede pasar un delegado que devuelve DateTime.Now durante la ejecución normal, y luego en su pase de prueba en otro delegado que devuelve una fecha fija, y afirmar el resultado en función de eso.

0

Una forma "común" de hacerlo es "falsificar" la fecha actual del sistema (que se puede hacer de varias maneras) y luego probar el código en fechas "conocidas".

Otra forma interesante es cambiar su aplicación a poco:

private DateTime GetEstimatedArrivalDate() 
{ 
    return GetEstimatedArrivalDate(DateTime.Now); 
} 

private DateTime GetEstimatedArrivalDate(DateTime forDate) 
{ 
    DateTime estimatedDate; 
    if (forDate.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = forDate.Date.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = forDate.Date.AddDays(5); 
    } 
    return estimatedDate; 
} 

Y a continuación, utilizar el método con un parámetro para probar en las fechas "inmediatas".

1

Voy a dar la respuesta polémica, no la pruebes.

La lógica es trivial y tiene cero dependencias, creo en una buena cobertura de código, pero no cuando aumenta la complejidad sin ninguna ganancia real.

+1

Eso suena razonable, pero este es exactamente el tipo de método que esperaría cambiar inesperadamente. Si la empresa cambia sus políticas de envío, comienza a ofrecer servicios por niveles o cambia de proveedor. Ahora, técnicamente, puedes comenzar a probarlo una vez que se complica, pero tiendo a pensar que esta es una bisagra significativa en la aplicación, y debe estar bajo prueba para que todo el mundo sepa el momento en que cambia. Por si acaso. – jcdyer

+0

Bah. ¿Qué sucede si decidimos cambiar las posiciones de jueves a viernes durante la semana? * Nunca se sabe que este código se rompió * hasta que fue * demasiado tarde. * Y si decidimos comenzar a contar días * hacia atrás *, bueno, entonces, ni siquiera sé * qué * decirle si puede No me muestre una luz roja parpadeante de "prueba fallida". ;) – Aaronaught

+0

Estoy de acuerdo con otros comentaristas. La lógica en este método es en realidad no trival. Lo hice simple solo con el propósito de mostrarlo como un ejemplo para mi pregunta. Quiero probarlo a fondo. –

9

En términos generales, que te gustaría para abstraer el método para obtener la fecha y hora actuales detrás de una interfaz, por ejemplo:

public interface IDateTimeProvider 
{ 
    DateTime Now { get; } 
} 

El servicio real sería:

public class DateTimeProvider: IDateTimeProvider 
{ 
    public DateTime Now 
    { 
     get 
     { 
      return DateTime.Now; 
     } 
    } 
} 

Y una el servicio de prueba sería:

public class TestDateTimeProvider: IDateTimeProvider 
{ 
    private DateTime timeToProvide; 
    public TestDateTimeProvider(DateTime timeToProvide) 
    { 
     this.timeToProvide = timeToProvide; 
    } 

    public DateTime Now 
    { 
     get 
     { 
      return timeToProvide; 
     } 
    } 
} 

Para los servicios que requieren la hora actual, haga que tomen una IDa teTimeProvider como una dependencia. Para el caso real, pase un nuevo DateTimeProvider(); cuando sea un componente, pase un nuevo TestDateTimeProvider (timeToTestFor).

+1

Le daré esto a + 1 porque es absolutamente correcto, pero al mismo tiempo siento que es un poco exagerado solo para probar un método de trival. Admiro tu dedicación a la cobertura, y probablemente adoptaría esto si hubiera muchos métodos o algún método complejo que necesitara pruebas :) –

+0

Puede ser trivial ahora, pero las cosas pueden cambiar fácilmente. De todos modos, +1 como ciertamente haría un adaptador alrededor de las clases de DateTime para permitir la prueba. Además, para un TDDer, esta sería la ruta normal. – Finglas

+0

En una nota al margen, ¿no sería mejor utilizar un marco de burla, en lugar de crear un "servicio de prueba" que ahora necesita mantener también? Parece un poco insensible? –

2

Haga su clase toma un IClock parámetro (a través de constructor o propiedad)

interface IClock 
{ 
    DateTime Now { get; } 
} 

A continuación, puede utilizar una aplicación falsa para probar

class FakeClock : IClock 
{ 
    DateTime Now { get; set } 
} 

y una aplicación real, el resto del tiempo.

class SystemClock : IClock 
{ 
    DateTime Now { get { return DateTime.Now; } } 
} 
0

Yo sugeriría hacer esto como Mark suggests, pero con la adición de una llamada sobrecargados para su uso en producción que toma ningún parámetro y utiliza DateTime.Now

private DateTime GetEstimatedArrivalDate() 
{ 
    return GetEstimatedArrivalDate(DateTime.Now); 
} 

private DateTime GetEstimatedArrivalDate(DateTime currentDate) 
{ 
    DateTime estimatedDate; 
    if (currentDate.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = currentDate.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = currentDate.AddDays(5); 
    } 
    return estimatedDate; 
} 
Cuestiones relacionadas