2016-10-09 1 views
0

.NET 래퍼 라이브러리를 만들려고하는 관리되지 않는 DLL이 있는데 그 대신에 NUnit(v3) 테스트를 실행할 때 다른 동작이 발생합니다 버튼에서 방금 실행하면 WinForm 앱을 클릭하십시오.Unit (Integration) 테스트에서 COM 구성 요소에서 이벤트가 발생하지 않음

배경 : DLL을 시작할 때 DLL을 궁극적으로 TCP 연결로 만드는 원인이되는 Connect() 메서드를 호출합니다. TCP 연결이 설정되면 처리기를 "연결됨"이벤트에 연결하여 알림을받습니다. 일단 연결되면 DLL에서 다른 명령을 호출합니다.

간단한 테스트 Winforms 앱에서 "DLL"을 인스턴스화 한 다음 Connect() 메서드를 호출하는 버튼이 하나 있습니다. 스레드가 완료되면 앱이 약 2 초 동안 유휴 상태가 된 다음 "connected"이벤트 처리기가 예상대로 작동합니다. 이벤트가 아무것도 반환하지 않습니다.

그러나

connect()는 비용이 많이 드는 작업입니다, 내 라이브러리가 큰 응용 프로그램 향하는 때문에, 나는 AutoResetEvent을 내 라이브러리에 ConnectAsync() 방법을 생성하고 async and await 키워드의 사용을했고, 때문에. ConnectAsync() 메서드는 TCP 연결이 이벤트에서 발생했다는 알림을 받으면 "인스턴스화 된"DLL의 인스턴스를 반환합니다. 테스트 WinForms 앱에 약간의 리팩터링이 적용되며 예상대로 작동합니다.

다음 단계는 NUnit을 사용하여 통합 테스트를 만드는 것입니다. 그러나 비동기 테스트에서 ConnectAsync() 메서드를 호출하면 원격 응용 프로그램에서 TCP 연결을 설정할 수 있지만 이벤트 처리기는 실행되지 않습니다. 1 일간의 테스트, 검색 및 시행 착오로 인해 ConnectAsync()은 UnitTest가 아닌 단순한 Winforms 버튼에서 완벽하게 작동합니다. 여기

는 테스트 코드

[Test()] 
public async Task Test1() 
{ 
    var conn = await GetConnection(); 
    //assert some commands on the conn 
} 

private async Task<TCPConnector> GetConnection() 
{ 
    return await Task.Run(() => 
    { 
     var mre = new AutoResetEvent(false);   
     var ctrl = new TCPConnector(); 
     ctrl.serverName = server; 
     ctrl.serverPort = serverPort; 
     ctrl.onConnected +=() => { mre.Set(); }; 
     ctrl.Connect(); 
     mre.WaitOne(); 
     return ctrl; 
    }); 
} 

난이 엄격하게 질문 아니라는 것을 알고,하지만 난 난처한 상황에 빠진 시도하는 아이디어를 찾고 있어요. 또는 버튼 클릭 이벤트와 NUnit 테스트 실행간에 다른 점에 대한 포인터. 사용이 작동 MSTEST 경우 경우

이 누군가에게 무언가를 의미한다, 나는 전화 했어 DLL은 관리되지 않는 ActveX에게

갱신 1입니다! 그래서 그것은 NUnit의 시작 환경과 관련이 있습니다.

갱신 2는 : this SO 게시물에 조사를 통해 , 나는 우연히 어떤 단위 테스트 프레임 워크없이 같은 동작을 복제, 대신 등록 무료 COM을 통해. COM이 활성화되고 소비되는 방식과 관련이 있다고 생각하고 있습니까?

해상도 마지막으로 대답을 찾았습니다. this에 대한 그의 대답은 Chris에게 귀속됩니다. 내가해야 할 일을했을 모든 설명 된대로 매니페스트에 <comInterfaceExternalProxyStub /> 섹션을 추가하고,

UPDATE 4

마지막 업데이트와 해상도를 무시 빙고이었다.COM, Regfree COM, Interop 및 COM Events의 전 세계를 작업하면서 오도 (misdirection)와 가양 성 (false positives), 내 이해가 부족합니다. 문제는 아직 해결되지 않았습니다.

COM이 단위 테스트의 컨텍스트에서 실행될 때 COM 이벤트가 발생하지 않는다는 것이 중요한 문제입니다. 평범한 .exe에서 실행하면 그들은 정상적으로 작동합니다.

+0

테스트 코드에 대한 자세한 내용을 제공합니다. –

+0

@OrdinaryOrange : 시도해 보겠습니다. [TaskCompletionSource' 사용] (https://msdn.microsoft.com/en-us/library/hh873178(v=vs.110) .aspx # EAP) 대신 'AutoResetEvent'를 사용하여 Task.Run을 실행하십시오. –

+0

스티븐에게 제안 해 주셔서 감사합니다. 제안 된대로 'TaskCompletionSource'를 사용하도록 코드를 리팩토링했지만 이전과 같은 결과를 얻고 있습니다. 나는 그것이 시작 환경 사이의 약간의 차이가되어야한다고 생각하고있다. – OrdinaryOrange

답변

0

정확하게 관리되지 않는 DLL이 무엇을하고 있는지 모른 채 내 생각에 단일 스레드 아파트 (STA) COM dll이라는 것입니다. 이 스레딩 모델에서 COM interop는 DLL에 대한 모든 호출을 객체를 생성하는 스레드에 마샬링합니다 (단위 테스트에서 자동 재설정 이벤트를 기다리는 동안 차단되므로 아무 일도 일어나지 않습니다).

기본 UI 스레드가 STA 스레드 (기본 메서드의 특성 확인)이고 메시지를 펌핑하기 때문에 이벤트 패턴이 Winforms 응용 프로그램에서 작동하므로 콜백이 허용되고 COM 메시지 펌핑으로 대체됩니다.

이 경우 래퍼를 테스트하는 유일한 방법은 STA 스레드를 만들고 메시지 펌프를 실행 한 다음 스레드에 메시지를 전달하여 COM 개체 및 연결 만들기를 트리거하는 것입니다 (다른 말로하면 커다란 고통). 더 나쁜 것은 개체가 클라이언트 응용 프로그램에서이 방식으로 작동한다는 것입니다. 따라서 래퍼에 STA 스레드를 만들고 모든 호출을 마샬링하지 않으면 비동기 적으로 사용할 수 없습니다.

+0

하 나는 이것을 시험해 보지 않았다. 그리고 나서 다시 여기로 와서 당신의 게시물을 보았다. 그래서 나는 곧바로 대답 할 수있다. 안타깝게도 행운이 없습니다. 나는 STA 스레드 ([이 질문] (http://stackoverflow.com/questions/1531512/activex-control-without-a-form)에서 접근 방식을 사용하여 호출을 래핑했지만 그 효과가 없었다. 나는 그것이 완벽하게 작동한다는 MSTest에서 실행하면 발견했습니다. 그래서 그것은 NUnit과 관련이 있습니다. – OrdinaryOrange

+0

STA 스레드가 작동하려면 펌핑이 필요하다는 것을 기억하십시오 ... –

+0

'Application.Idle' 이벤트 안에'Connect()'를 넣어서 확인하십시오. 'Connect()'가 실행되고 원격 측에서 연결을 볼 수 있었지만'onConnect' 이벤트는 여전히 실행되지 않습니다. – OrdinaryOrange

관련 문제