2011-12-14 5 views
7

우리는 C++로 작성된 집에서 만든 COM 구성 요소가 있습니다. 이제 C# 테스트 프로젝트에서 함수와 이벤트를 테스트하려고합니다. 기능 테스트는 꽤 간단합니다. 그러나 이벤트는 트리거되지 않습니다.COM 이벤트 단위 테스트 중이십니까?

MyLib.MyClass m = new MyLib.MyClass(); 
Assert.IsTrue(m.doStuff()); // Works 

// This does not work. OnMyEvent is never called! 
m.MyEvent += new MyLib.IMyClassEvents_MyEventHandler(OnMyEvent); 
m.triggerEvent(); 

나는이를 봤 여기에 StackOverflow에 유사한 문제에 대해 읽었습니다. 나는 모든 제안 된 방법을 시도했지만 작동시키지 못한다!

지금까지 active dispatcher으로 테스트를 실행 해 보았지만 성공하지 못했습니다. 또한 Dispatcher.PushFrame()을 사용하여 수동으로 메인 스레드에서 메시지를 펌핑 해 보았습니다. 아무것도. 내 사건은 결코 실행되지 않습니다. 간단한 WinForms 프로젝트를 만들고 이벤트가 정상적으로 작동하는지 확인했습니다. 따라서이 문제는 단위 테스트에만 적용됩니다.

Q : 활성 이벤트 처리기를 성공적으로 트리거 할 수있는 일반 C# Unit Test를 만들려면 어떻게해야합니까?

거기 밖으로 누군가가 작동 샘플을 가지고 있어야합니다! 도와주세요.

+0

단위 테스트에 실패했습니다. COM 서버는 이벤트를 생성하기 전에 메시지 루프를 펌핑하는 프로그램이 필요합니다. 그것은 STA 계약의 일부입니다. 지원을 받으려면 구성 요소 작성자에게 문의하십시오. –

+0

COM 서버는 우리 자신의 구성 요소입니다.이 구성 요소를 테스트하고 싶습니다. 당신이 말하는 것처럼, 메시지를 펌핑하는 것이 필수적입니다. 그래서 질문은 남아 있습니다. 어떻게 단위 테스트에서 이것을 수행합니까? – l33t

+0

@NOPslider 어떤 단위 테스트 프레임 워크를 사용하고 있습니까? 최신 버전의 NUnit은 기본적으로 MTA 스레딩 모델을 사용합니다. – vcsjones

답변

1

COM 개체가 STA 개체 인 경우 이벤트를 발생 시키려면 메시지 루프를 실행해야 할 수 있습니다.

ApplicationForm 개체 주위에 작은 포장을 사용하여이를 수행 할 수 있습니다. 다음은 몇 분 안에 작성한 작은 예입니다.

실행 또는 테스트하지 않았으므로 작동하지 않을 수 있으며 정리가 더 잘 수행되어야합니다. 그러나 그것은 당신에게 해결책을 제시 할 수 있습니다.

public interface IMessageLoopTestRunner 
{ 
    void Finish(); 
} 

public class MessageLoopTestRunner : Form, IMessageLoopTestRunner 
{ 
    public static void Run(Action<IMessageLoopTestRunner> test, TimeSpan timeout) 
    { 
     Application.Run(new MessageLoopTestRunner(test, timeout)); 
    } 

    private readonly Action<IMessageLoopTestRunner> test; 
    private readonly Timer timeoutTimer; 

    private MessageLoopTestRunner(Action<IMessageLoopTestRunner> test, TimeSpan timeout) 
    { 
     this.test = test; 
     this.timeoutTimer = new Timer 
     { 
      Interval = (int)timeout.TotalMilliseconds, 
      Enabled = true 
     }; 

     this.timeoutTimer.Tick += delegate { this.Timeout(); }; 
    } 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     // queue execution of the test on the message queue 
     this.BeginInvoke(new MethodInvoker(() => this.test(this))); 
    } 

    private void Timeout() 
    { 
     this.Finish(); 
     throw new Exception("Test timed out."); 
    } 

    public void Finish() 
    { 
     this.timeoutTimer.Dispose(); 
     this.Close(); 
    } 
} 

가 도움을합니까 : 그런 일이 될 것입니다

[TestMethod] 
public void Test() 
{ 
    MessageLoopTestRunner.Run(

     // the logic of the test that should run on top of a message loop 
     runner => 
     { 
      var myObject = new ComObject(); 

      myObject.MyEvent += (source, args) => 
      { 
       Assert.AreEqual(5, args.Value); 

       // tell the runner we don't need the message loop anymore 
       runner.Finish(); 
      }; 

      myObject.TriggerEvent(5); 
     }, 

     // timeout to terminate message loop if test doesn't finish 
     TimeSpan.FromSeconds(3)); 
} 

그리고 MessageLoopTestRunner에 대한 코드 :이 방법을 사용

, 테스트 클래스는 다음과 같이 보일 것이다?