2008-10-20 2 views
0

나는 호출하고있는 객체로부터 이벤트를 받기를 기대하는 테스트를 작성하고있다. 특히, 오픈 소스 Granados 프로젝트를 사용하여 SSH를 통해 AIX 시스템에 연결하는 객체를 호출 한 다음 연결을 끊고 연결 해제 중에 발생하는 OnConnectionClosed 이벤트를 수신하고 싶습니다. 그것은 아주 간단하게 들리지만 나는 과거에 이렇게 많은 테스트를 작성했지만, 이번에는 스레딩과 관련이 있다고 생각되는 이상한 행동이 일어나고 있습니다.다른 스레드에서 발생시킬 이벤트를 수신하는 MSTest 유닛 테스트를 작성하는 방법은 무엇입니까?

기본적으로 내가 호출하는 객체는 내가 호출 한 것과 다른 스레드에서 'OnConnectionClosed'이벤트를 발생시키고 있습니다. 내가보기 엔 UI에서 'Debug Test'를 선택하여 테스트를 실행하면 통과하지만 'Run Test'를 선택하면 디버그 실행 중 중단 점이 설정되지 않은 경우에도 실패합니다. 내가 검색 좀 해봤으며 기본적으로 MSTest 호스트가 단일 스레드 모드에서 실행되지만 구성 변경으로 인해 다중 스레드 모드에서 실행될 수 있다는 것을 나타내는 것으로 보이는 this post을 발견했습니다. 이것은 논리적으로 내 문제를 해결하는 것처럼 들리 겠지만 물론 그렇지 않습니다.

다른 게시물들 나는 또한 MSTest가 단순히 백그라운드 스레드를 모니터링하지 않는다고 생각하게 만듭니다. (그래서 그들에 의해 제기 된 이벤트는 '들었습니다'). 이것은 또한 이해가 될 것이고, 디버그 모드에서 작동하는 것 같고 위의 수정이 논리적으로이 문제를 해결해야하는 것처럼 보입니다. 그런 다음 왜 작동하지 않는지 혼란 스럽습니다. 디버그 모드에서 여전히 문제가 있다고 생각할지라도 스레드를 제대로 처리하지 못하는 것일 수 있습니다.

비슷한 방식으로 다른 사람이 뭔가를 시도한 적이 있습니까? 그렇다면 비슷한 문제가 발생 했습니까? 그렇다면 어떻게 해결 했습니까?

아래 관련 단위 테스트 코드를 붙여 넣었습니다 (보안상의 이유로 연결 정보가 삭제되었습니다).

[TestClass] 
public class SSHReaderTests 
{ 
    private bool received = false; 
    private delegate bool SimpleFunc(); 

    [TestInitialize] 
    public void MyTestInitialize() 
    { 
     received = false; 
    } 

    [TestMethod] 
    public void Should_raise_OnReaderConnectionClosed_event_after_successful_connection_is_disconnected() 
    { 
     IReader reader = new SSHReader(); 

     reader.OnReaderConnectionClosed += delegate 
            { 
             received = true; 
            }; 

     reader.Connect("*****", "*****", "*****"); 

     //Assert.IsTrue(reader.IsConnected); 

     reader.Disconnect(); 

     //Assert.IsFalse(reader.IsConnected); 

     Assert.IsTrue(WaitUntilTrue(delegate { 
      return received; }, 30000, 1000)); 
    } 

    private static bool WaitUntilTrue(SimpleFunc func, int timeoutInMillis, int timeBetweenChecksInMillis) 
    { 
     Stopwatch stopwatch = new Stopwatch(); 
     stopwatch.Start(); 

     while(stopwatch.ElapsedMilliseconds < timeoutInMillis) 
     { 
      if (func()) 
       return true; 

      Thread.Sleep(timeBetweenChecksInMillis); 
     } 
     return false; 
    } 
} 

답변

2

System.Threading 네임 스페이스의 WaitHandle 클래스를 사용하십시오. AutoResetEvent 또는 ManualResetEvent입니다. 두 가지의 차이점은 AutoResetEvent가 설정 될 때마다 한 스레드가 진행될 수 있으며 ManualResetEvent는 대기중인 모든 스레드를 해제합니다.

예제가 작동하지 않는 이유는 컴파일러 최적화와 관련이 있습니다. 이 코드는 언뜻 생각하면 실제로 컴파일되지 않습니다. 대부분 컴파일러는 레지스터에 로컬 변수를 배치하고 실제로 루프를 검사하는 동안 실제로 가져 오지 않는 것과 같은 작업을 수행합니다. 휘발성 키워드를 사용하면 이러한 유형의 문제를 피할 수 있지만 자세한 내용은 스레딩 및 동시성에 대한 정보를 읽는 것이 좋습니다. Joe Duffy의 블로그 http://www.bluebytesoftware.com은 시작하기에 좋은 자료이며 곧 나오는 Windows 동시성 프로그래밍 (Concurrency Programming on Windows)을 적극 권장합니다.

0

당신이 궁금해하는 것은 아니지만, CHESS이라는 MS Research 프로젝트를 살펴보면 실행 가능한 해결책이나 아이디어가있을 수 있습니다. 이것은 .net의 멀티 스레드 동시성 테스트 용입니다.

관련 문제