2012-01-20 8 views
13

Próbuję uruchomić procedurę obsługi zdarzeń przypisaną do mojego symulatora zegarowego. Jak mogę przetestować tę prywatną metodę tutaj?Jak uruchomić procedurę obsługi zdarzeń przypisaną do próby?

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

Klasy klienta przypisuje obiekt obsługi zdarzeń do tego obiektu. Chcę przetestować logikę w tej klasie.

_timer.Elapsed += ResetExpiredCounters; 

I przypisana metoda jest prywatny

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

Chcę mieć ten obsługi zdarzeń w moim mock i uruchomić go jakoś. Jak mogę to zrobić?

Aktualizacja:

zdałem sobie sprawę, podnoszenie zdarzenie zanim przypisane obsługi zdarzeń. Poprawiłem to, ale ja wciąż dostać ten błąd:

wzniosę ją tak:

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

lub

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

Obie nie będzie działać.

Aktualizacja:

Oto rzeczy, że pracował dla mnie. Zauważ, że nie jest to przydatne, jeśli próbujesz przekazać informacje do obsługi zdarzeń, jak Jon wskazał w komentarzach. Używam go tylko do kpiny z wrappera dla klasy System.Timers.Timer.

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

W ostatecznym rozrachunku nie pomoże to wcale, jeśli trzeba użyć argumentów zdarzeń, ponieważ zawsze będzie to wartość NULL. Jednak jest to jedyny sposób, ponieważ ElapsedEventArgs ma tylko wewnętrzny konstruktor.

+0

„Obiekt typu«System.EventArgs»nie może przekonwertować , aby wpisać "System.Timers.ElapsedEventArgs" "- Jaka część jest niejasna? – Groo

+0

Nadal dostaję ten błąd, nawet jeśli przekażę ElapsedEventArgs. Jak mogę podnieść to wydarzenie? –

+0

Czy "ElapsedEventHandler" w interfejsie 'ITimer' naprawdę' System.Timers.ElapsedEventHandler'? – Groo

Odpowiedz

10

ElapsedEventArgs posiada prywatny konstruktor i nie może być instancja.

Jeśli używasz:

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

Następnie opiekun będzie recevie null parametr i straci swoją SignalTime właściwość:

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

Możesz chcieć ten parametr w niektórych przypadkach.

Aby rozwiązać ten problem i uczynić go bardziej sprawdzalne, stworzyłem również otoki dla ElapsedEventArgs i wykonany interfejs używać go:

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(); 
} 

Realizacja po prostu odpalić własne wydarzenie uzyskaniu danych z rzeczywistym zdarzenie timera:

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; 
     } 
    } 
} 

teraz można uprościć i poprawić makiety tego wydarzenia:

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

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

Mniej kodu do napisania, łatwiejszy w pracy i całkowicie oddzielony od struktury.

+1

+1 Dobra robota ... –

+1

Po prostu nie mogę zrozumieć, dlaczego ElapsedEventArgs ma prywatnego konstruktora, wymagającego tego szaleństwa. dzięki wam obojgu za wskazó[email protected], byłoby pomocne, jeśli pokażesz pełną implementację TimerWrapper. W końcu to rozwiązałem, ale zajęło mi to kilka minut. – Brett

+0

@Brett Code updated :) – JoanComasFdz

5

Sekcja dotycząca zdarzeń zawiera część Moq QuickStart guide. Myślę, że byłoby użyć

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

Przypisany moduł obsługi z klasy klienta nie działa? Czy czegoś brakuje? Czy nie powinienem mówić, żeby wyśmiać ratownika? –

+0

@ UfukHacıoğulları: Wierzę, że fikcja będzie po prostu pamiętała wszystkie dodane procedury obsługi. Proponuję zacząć od wyjścia z twojego * prawdziwego * kodu i po prostu eksperymentuj z przykładowym wydarzeniem, dopóki nie udowodnisz jak działa Moq, a następnie wróć do swojego prawdziwego kodu. –

+0

Wygląda na to, że nie działa program obsługi zdarzeń. –

0

czynienia z tym ostatnim, można skonstruować ElapsedEventArgs stosując odbicie:

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; 
    } 

ten sposób można kontynuować przy użyciu oryginalnego ElapsedEventHandler delegata

var yesterday = DateTime.Now.AddDays(-1); 
timer.Raise(item => item.Elapsed += null, CreateElapsedEventArgs(yesterday)); 
Powiązane problemy