2012-01-20 14 views
13

Estoy intentando disparar el controlador de eventos asignado a mi simulación de temporizador. ¿Cómo puedo probar este método privado aquí?¿Cómo puedo ejecutar el controlador de eventos asignado a un simulacro?

public interface ITimer 
{ 
    void Start(); 
    double Interval { get; set; } 
    event ElapsedEventHandler Elapsed; 
} 

La clase de cliente asigna un controlador de eventos a este objeto. Quiero probar la lógica en esta clase.

_timer.Elapsed += ResetExpiredCounters; 

Y el método asignado es privado

private void ResetExpiredCounters(object sender, ElapsedEventArgs e) 
{ 
    // do something 
} 

quiero tener este controlador de eventos en mi maqueta y ejecutarlo de alguna manera. ¿Cómo puedo hacer esto?

Actualización:

me di cuenta que estaba criando el evento antes de que yo le asigna el controlador de eventos. Corregí eso, pero sigo teniendo este error:

planteo así:

_timer.Raise(item => item.Elapsed += null, ElapsedEventArgs.Empty); 

o

_timer.Raise(item => item.Elapsed += null, EventArgs.Empty); 

Ambos no va a funcionar.

Actualización:

Aquí es lo que funcionó para mí. Tenga en cuenta que no es útil si está tratando de pasar información al controlador de eventos como Jon señaló en los comentarios. Solo lo estoy usando para burlarme del wrapper de la clase System.Timers.Timer.

_timer.Raise(item => item.Elapsed += null, new EventArgs() as ElapsedEventArgs); 

Al final, esto no ayudará en absoluto si es necesario utilizar argumentos del evento, ya que será siempre nula. Sin embargo, es la única forma, ya que ElapsedEventArgs solo tiene un constructor interno.

+0

"objeto de tipo 'System.EventArgs' no puede Convierta para escribir 'System.Timers.ElapsedEventArgs' "- ¿Qué parte no está clara? – Groo

+0

Todavía obtengo ese error incluso si paso ElapsedEventArgs. ¿Cómo puedo plantear ese evento? –

+0

Es 'ElapsedEventHandler' en su interfaz' ITimer' realmente 'System.Timers.ElapsedEventHandler'? – Groo

Respuesta

10

ElapsedEventArgs tiene un constructor privado y no se pueden crear instancias.

Si utiliza:

timer.Raise(item => item.Elapsed += null, new EventArgs() as ElapsedEventArgs); 

A continuación, el controlador se recevie un parámetro nulo y sin perder su propiedad SignalTime:

private void WhenTimerElapsed(object sender, ElapsedEventArgs e) 
{ 
    // e is null. 
} 

Es posible que desee este parámetro en algunos casos.

Para resolver esto y hacerlo más comprobable, también creé un contenedor para el ElapsedEventArgs, e hice la interfaz de usarlo:

public class TimeElapsedEventArgs : EventArgs 
{ 
    public DateTime SignalTime { get; private set; } 

    public TimeElapsedEventArgs() : this(DateTime.Now) 
    { 
    } 

    public TimeElapsedEventArgs(DateTime signalTime) 
    { 
     this.SignalTime = signalTime; 
    } 
} 

public interface IGenericTimer : IDisposable 
{ 
    double IntervalInMilliseconds { get; set; } 

    event EventHandler<TimerElapsedEventArgs> Elapsed; 

    void StartTimer(); 

    void StopTimer(); 
} 

La aplicación simplemente disparar su propio evento de obtener los datos de lo real evento de temporizador:

public class TimerWrapper : IGenericTimer 
{ 
    private readonly System.Timers.Timer timer; 

    public event EventHandler<TimerElapsedEventArgs> Elapsed; 

    public TimeSpan Interval 
    { 
     get 
     { 
      return this.timer.Interval; 
     } 
     set 
     { 
      this.timer.Interval = value; 
     } 
    } 

    public TimerWrapper (TimeSpan interval) 
    { 
     this.timer = new System.Timers.Timer(interval.TotalMilliseconds) { Enabled = false }; 
     this.timer.Elapsed += this.WhenTimerElapsed; 
    } 

    private void WhenTimerElapsed(object sender, ElapsedEventArgs elapsedEventArgs) 
    { 
     var handler = this.Elapsed; 
     if (handler != null) 
     { 
      handler(this, new TimeElapsedEventArgs(elapsedEventArgs.SignalTime)); 
     } 
    } 

    public void StartTimer() 
    { 
     this.timer.Start(); 
    } 

    public void StopTimer() 
    { 
     this.timer.Stop(); 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.disposed) 
     { 
      if (disposing) 
      { 
       this.timer.Elapsed -= this.WhenTimerElapsed; 
       this.timer.Dispose(); 
      } 

      this.disposed = true; 
     } 
    } 
} 

Ahora, puede simplificar y mejorar la maqueta de este evento:

timer.Raise(item => item.Elapsed += null, new TimeElapsedEventArgs()); 

var yesterday = DateTime.Now.AddDays(-1); 
timer.Raise(item => item.Elapsed += null, new TimeElapsedEventArgs(yesterday)); 

Menos código para escribir, más fácil de trabajar y totalmente desacoplado del marco.

+1

+1 Buen trabajo ... –

+1

Simplemente no entiendo por qué ElapsedEventArgs tiene un constructor privado, necesitando esta locura. gracias a ambos por la guí[email protected], sería útil mostrar la implementación completa de TimerWrapper. Eventualmente lo solucioné, pero me tomó unos minutos. – Brett

+0

@Brett Code updated :) – JoanComasFdz

5

El Moq QuickStart guide tiene una sección sobre los acontecimientos. Creo que tendría que utilizar

mock.Raise(m => m.Elapsed += null, new ElapsedEventArgs(...)); 
+0

¿El controlador asignado de la clase de cliente no parece ejecutarse? ¿Me estoy perdiendo de algo? ¿No debería estar diciendo que se burle de guardar el controlador? –

+0

@ UfukHacıoğulları: Creo que el simulacro simplemente recordará los controladores que se agregan. Sugeriría que comiences saliendo de tu código * real *, y solo experimentas con un evento de muestra hasta que hayas probado cómo funciona Moq, luego regresa a tu código real. –

+0

Parece que no ejecuta el controlador de eventos en absoluto –

0

ocupado de esto recientemente, se puede construir un ElapsedEventArgs utilizando la reflexión:

public ElapsedEventArgs CreateElapsedEventArgs(DateTime signalTime) 
    { 
     var e = FormatterServices.GetUninitializedObject(typeof(ElapsedEventArgs)) as ElapsedEventArgs; 
     if (e != null) 
     { 
      var fieldInfo = e.GetType().GetField("signalTime", BindingFlags.NonPublic | BindingFlags.Instance); 
      if (fieldInfo != null) 
      { 
       fieldInfo.SetValue(e, signalTime); 
      } 
     } 

     return e; 
    } 

esta manera se puede seguir utilizando el delegado ElapsedEventHandler originales

var yesterday = DateTime.Now.AddDays(-1); 
timer.Raise(item => item.Elapsed += null, CreateElapsedEventArgs(yesterday)); 
Cuestiones relacionadas