2012-01-20 3 views
13

타이머 모의 작업에 할당 된 이벤트 처리기를 시작하려고합니다. 이 비공개 방법을 여기서 어떻게 테스트 할 수 있습니까?모의 객체에 할당 된 이벤트 핸들러를 어떻게 실행할 수 있습니까?

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

클라이언트 클래스는이 개체에 이벤트 처리기를 할당합니다. 이 수업에서 논리를 테스트하고 싶습니다.

_timer.Elapsed += ResetExpiredCounters; 

그리고 할당 방법은

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

개인이다 나는 나의 모의에서이 이벤트 핸들러가 어떻게 든 그것을 실행하려는. 어떻게해야합니까?

업데이트 :

가 나는 이벤트 핸들러를 할당하기 전에이 이벤트를 발생 깨달았다. 나는 그것을 수정하지만, 난 여전히이 오류를 얻을 :

내가 이런 식으로 인상 :

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

또는

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

가 모두 작동하지 않습니다를.

는 업데이트 :

여기에 나를 위해 일한 것입니다. Jon이 주석에서 지적한 것처럼 이벤트 처리기에 정보를 전달하려는 경우 유용하지 않습니다. 난 그냥 System.Timers.Timer 클래스에 대한 래퍼를 조롱하는 데 사용하고 있습니다.

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

결국 항상 null이 될 수 있으므로 이벤트 인수를 사용해야하는 경우에는 결국 도움이되지 않습니다. 그러나 ElapsedEventArgs에는 내부 생성자 만 있기 때문에이 방법이 유일한 방법입니다.

+0

"타입의 객체의 경우 System.EventArgs '원래 ElapsedEventHandler 대리자를 할 수 계속 사용할 수 있습니다이 방법 : – Groo

+0

ElapsedEventArgs를 전달하더라도 여전히 오류가 발생합니다. 어떻게 그 사건을 제기 할 수 있습니까? –

+0

'ITimer' 인터페이스의'ElapsedEventHandler'는 실제로'System.Timers.ElapsedEventHandler'입니까? – Groo

답변

10

ElapsedEventArgs 개인 생성자가 인스턴스화 할 수없는 사용하는 거라고 생각합니다.

당신이 사용하는 경우 :

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

그런 다음 핸들러가 널 매개 변수를 recevie하고 SignalTime 속성을 잃게됩니다 :

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

당신은 어떤 경우에는이 매개 변수를 할 수 있습니다.

이 문제를 해결하고 더 검증하기 위해, 나는 또한 ElapsedEventArgs의 래퍼를 생성, 인터페이스는 사용했다 :

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

단순히 자신의 이벤트가 실제의 데이터를 받고 실행됩니다 구현 타이머 이벤트 : 이제

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

, 당신은 단순화하고이 이벤트의 모의 향상시킬 수

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

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

작성하기가 쉽지 않고 작업하기가 쉽지 않고 프레임 워크에서 완전히 분리되었습니다.

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

당신이

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

+1 잘 했어 ... –

+1

설계되지 않았다 보인다. 어쨌든, 두 분 모두에게 감사드립니다[email protected] JoanComasFdz, TimerWrapper의 전체 구현을 보여 주면 도움이 될 것입니다. 나는 결국 그것을 분류했지만 몇 분이 걸렸습니다. – Brett

+0

@Brett 코드가 업데이트되었습니다. :) – JoanComasFdz

5

Moq QuickStart guide에는 이벤트 섹션이 있습니다. 난 당신이

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

클라이언트 클래스에서 할당 된 처리기가 실행되지 않는 것 같습니까? 내가 놓친 게 있니? 처리기를 모의하고 싶다는 말을하면 안 될까요? –

+0

@ UfukHacıoğulları : 나는 모의이 추가되는 모든 핸들러를 기억할 것이라고 믿습니다. 실제 코드에서 벗어나 Moq의 작동 방식을 입증 할 때까지 샘플 이벤트를 실험 해본 다음 실제 코드로 돌아가는 것으로 시작하는 것이 좋습니다. –

+0

이 UfukHacıoğulları @ 모든 –

0

은 반사 사용하여 ElapsedEventArgs을 구성 할 수 있습니다, 최근이 처리 을 'System.Timers.ElapsedEventArgs' '형식으로 변환해야합니다. "- 어떤 부분이 불분명합니까?
관련 문제