2010-03-02 21 views

Respuesta

9

Puede probar la unidad no creando realmente una dependencia directa en System.Threading.Timer. En su lugar, cree una interfaz ITimer y un contenedor alrededor de System.Threading.Timer que la implemente.

primer lugar usted necesita para convertir la devolución de llamada a un evento, por lo que se puede hacer parte de una interfaz:

public delegate void TimerEventHandler(object sender, TimerEventArgs e); 

public class TimerEventArgs : EventArgs 
{ 
    public TimerEventArgs(object state) 
    { 
     this.State = state; 
    } 

    public object State { get; private set; } 
} 

A continuación, cree una interfaz:

public interface ITimer 
{ 
    void Change(TimeSpan dueTime, TimeSpan period); 
    event TimerEventHandler Tick; 
} 

Y un envoltorio:

public class ThreadingTimer : ITimer, IDisposable 
{ 
    private Timer timer; 

    public ThreadingTimer(object state, TimeSpan dueTime, TimeSpan period) 
    { 
     timer = new Timer(TimerCallback, state, dueTime, period); 
    } 

    public void Change(TimeSpan dueTime, TimeSpan period) 
    { 
     timer.Change(dueTime, period); 
    } 

    public void Dispose() 
    { 
     timer.Dispose(); 
    } 

    private void TimerCallback(object state) 
    { 
     EventHandler tick = Tick; 
     if (tick != null) 
      tick(this, new TimerEventArgs(state)); 
    } 

    public event TimerEventHandler Tick; 
} 

Obviamente se agregarían las sobrecargas del constructor y/o Change método que necesita usar desde el Threading.Timer. Ahora puede probar la unidad nada dependiendo de ITimer con un temporizador falsa:

public class FakeTimer : ITimer 
{ 
    private object state; 

    public FakeTimer(object state) 
    { 
     this.state = state; 
    } 

    public void Change(TimeSpan dueTime, TimeSpan period) 
    { 
     // Do nothing 
    } 

    public void RaiseTickEvent() 
    { 
     EventHandler tick = Tick; 
     if (tick != null) 
      tick(this, new TimerEventArgs(state)); 
    } 

    public event TimerEventHandler Tick; 
} 

Cada vez que desee simular una garrapata, simplemente llame a RaiseTickEvent en las falsificaciones.

[TestMethod] 
public void Component_should_respond_to_tick 
{ 
    ITimer timer = new FakeTimer(someState); 
    MyClass c = new MyClass(timer); 
    timer.RaiseTickEvent(); 
    Assert.AreEqual(true, c.TickOccurred); 
} 
+0

Esto se ve bien, pero ¿por qué creas tu propio delegado en lugar de simplemente usar el delegado TimerCallback del BCL? – Shaun

+1

@Shaun: Porque ese delegado no es un controlador de eventos válido. Los manejadores de eventos tienen una firma específica: 'object sender, TEventArgs e' donde' TEventArgs: EventArgs'. – Aaronaught

+0

Eso sí, estos días con cierres que se soportan tan fácilmente, si quisiera algo rápido y sucio, no sé si me molestaría con toda la declaración del evento y el cableado, podría simplemente pasar una 'Acción 'en cambio. – Aaronaught

1

voy a probarlo en el de la misma manera que cualquier otra clase pero con intervalos de tiempo cortos para evitar que la prueba de la unidad se ejecute durante un tiempo prolongado. Otro enfoque es probar tu propio código solo y usar un temporizador simulado (por ejemplo, NMock), pero depende de cómo sea el diseño de tu código. ¿Puedes publicar algunos fragmentos de código?

0

Si el tiempo simplemente cambia el método de devolución de llamada, entonces solo necesita verificar la exactitud de ese método, no cómo funciona la hora del sistema.

Además de eso, recomiendo usar el MultimediaTimer en su lugar - es mucho más preciso.

+0

Digamos que quiero un temporizador que se enciende una vez por hora. ¿Recomiendas el 'MultimediaTimer' para todos? :) –

+0

Sí, y combínelo con .NET's Dispatcher si necesita devolver el hilo de la interfaz de usuario. –

0

Afortunadamente cualquiera que sea esta característica es una parte más grande de permite configurar el intervalo del temporizador. Debería poder usar esa interfaz para inyectar un breve intervalo adecuado para la prueba unitaria. Tengo la pregunta el valor de esta prueba: ¿Estás probando el intervalo (sin sentido) o que la rutina se llama aproximadamente cada cierto tiempo?