2010-07-19 63 views
4

我目前工作的一些基於.NET的軟件時,隔離不好的COM組件(HP質量中心10.0)(.NET Framework 3.5 SP1中)與惠普質量中心10.0集成通過它的COM客戶端API(通常被稱爲TDApiOle80或TDApiOle80.TDConnection)。如何從.NET應用程序進行集成測試

我們正在使用的xUnit 1.6.1.1521和加利奧3.1.397.0(從一個MSBuild文件調用)

我們經歷的過程:

  • 創建連接
  • 運行測試
  • 結算連接
  • 處置
  • 強制GC.Collection()/ GC.AwaitingPendingFinalizers( )

對於每個集成測試 - 並且每個集成測試都在其事實中配置的超時運行。

我們的問題是,它出現了一些測試之後(比如大約10個左右),質量中心塊稱爲無限時 - 和整個加利奧的凍結,將不再回應。

最初我們發現xunit.net只應用了事實中的代碼超時 - 所以它會無限期地等待構造函數或者處理方法來完成 - 所以我們將這個邏輯移到了測試體中,以確認......但這並沒有解決這個問題(仍然掛在天邊一定數量的測試之後)。

使用TestDriven.Net時會發生同樣的情況 - 可以交互式運行1個或幾個測試,但更多的是大約10個測試,整個運行凍結 - 我們唯一的選擇是殺死TD使用的ProcessInvocation86.exe進程。淨。

有沒有人有任何提示/技巧,要麼如何阻止這一切發生在一起,要麼至少將我的集成測試與這些類型的問題隔離開來 - 以便QC API無限期地阻止測試,測試將失敗超時並允許Gallio移動到下一個測試。

更新

傾向於使用STA線程的提示,幫助移動問題上向前邁進了一下 - 通過自定義屬性XUnit.Net我們現在在它自己的STA線程啓動測試。這已停止加利奧/ TestDriven.Net從完全鎖定了,這樣我們就可以包括運行我們的哈德森構建服務器上的集成測試。

public class StaThreadFactAttribute : FactAttribute 
    { 
     const int DefaultTime = 30000; // 30 seconds 

     public StaThreadFactAttribute() 
     { 
      Timeout = DefaultTime; 
     } 

     protected override System.Collections.Generic.IEnumerable<Xunit.Sdk.ITestCommand> EnumerateTestCommands(Xunit.Sdk.IMethodInfo method) 
     { 
      int timeout = Timeout; 

      Timeout = 0; 

      var commands = base.EnumerateTestCommands(method).ToList(); 

      Timeout = timeout; 

      return commands.Select(command => new StaThreadTimeoutCommand(command, Timeout, method)).Cast<ITestCommand>(); 
     } 
    } 

    public class StaThreadTimeoutCommand : DelegatingTestCommand 
    { 
     readonly int _timeout; 
     readonly IMethodInfo _testMethod; 

     public StaThreadTimeoutCommand(ITestCommand innerComand, int timeout, IMethodInfo testMethod) 
      : base(innerComand) 
     { 
      _timeout = timeout; 
      _testMethod = testMethod; 
     } 

     public override MethodResult Execute(object testClass) 
     { 
      MethodResult result = null; 

      ThreadStart work = delegate 
                { 
                 try 
                 { 
                  result = InnerCommand.Execute(testClass); 
                  var disposable = testClass as IDisposable; 
                  if (disposable != null) disposable.Dispose(); 
                 } 
                 catch (Exception ex) 
                 { 
                  result = new FailedResult(_testMethod, ex, this.DisplayName); 
                 } 
                }; 

      var thread = new Thread(work); 

      thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA 

      thread.Start(); 

      if (!thread.Join(_timeout)) 
      { 
       return new FailedResult(_testMethod, new Xunit.Sdk.TimeoutException((long)_timeout), base.DisplayName); 
      } 

      return result; 
     } 
    } 

相反,我們現在看到的運行時TestDriven.Net測試這樣的輸出 - 順便說一句運行相同的套件幾次要麼導致所有測試通過,或通常只是1或兩個失敗的測試。和第一次失敗之後,在這第二次失敗的結果「錯誤而卸載應用程序域」的問題。

測試 'IntegrationTests.Execute_Test1' 失敗:測試執行時間超過: 30000ms

測試 「T:IntegrationTests。Execute_Test2' 失敗:卸載時出錯 appdomain。 (異常來自HRESULT: 0x80131015) System.CannotUnloadAppDomainException: 卸載appdomain時出錯。在System.AppDomain.Unload(應用程序域 域)處 Xunit.Runner.TdNet.TdNetRunner.TestDriven.Framework.ITestRunner.RunMember Xunit.ExecutorWrapper.Dispose()(ITestListener 聽者 : (0x80131015從HRESULT異常) ,裝配組件, 的MemberInfo構件)在 TestDriven.TestRunner.AdaptorTestRunner.Run(ITestListener testListener,ITraceListener 的TraceListener,字符串assemblyPath, 字符串testPath)在 TestDriven.TestRunner.ThreadTestRunner.Runner.Run()

4通過,2失敗,0跳過,拿到了 50.42秒(xunit)。

我還沒有確定爲什麼Quality Center API隨機無限期懸掛 - 很快就會進行調查。

更新27/07/2010

我終於確立了掛的原因 - 這裏是有問題的代碼:

connection = new TDConnection(); 
connection.InitConnectionEx(credentials.Host); 
connection.Login(credentials.User, credentials.Password); 
connection.Connect(credentials.Domain, credentials.Project); 
connection.ConnectProjectEx(credentials.Domain, credentials.Project, credentials.User, credentials.Password); 

看來,調用connect之後ConnectProjectEx有機會的阻塞(但它是非確定性的)。刪除冗餘連接的呼叫似乎增加了測試的穩定性顯着 - 正確的連接代碼:

connection = new TDConnection(); 
connection.InitConnectionEx(credentials.Host); 
connection.ConnectProjectEx(credentials.Domain, credentials.Project, credentials.User, credentials.Password); 

繼承了代碼庫我沒有過多考慮的連接代碼。

我還沒有弄清楚的一件事是爲什麼即使使用上面包含的超時代碼,Thread.Join(timeout)也不會返回。你可以附加一個調試器,它只是顯示測試線程正在加入/等待操作。也許在STA線程中執行一些操作?

+3

所以當他們把它稱爲「質量中心」,他們只是被諷刺? – Gabe 2010-07-19 02:44:26

+0

我們只是說我不是產品的粉絲 - 哦,對於產品中的肥皂或REST服務:) – Bittercoder 2010-07-19 04:09:34

+0

我們在OTA/TDApiOle80上爲QC 10執行了數百次集成測試,沒有問題或阻塞。所以理論上你應該可以做同樣的事情。 您是否嘗試解決阻塞本身的下劃線問題。 也許最好理解它爲什麼會阻塞,而不是試圖解決問題。 – 2010-07-19 20:21:48

回答

1

您可以嘗試在單獨的線程上運行您的代碼,然後在超時的新線程上調用Join,並在超時時中止它。

例如:

static readonly TimeSpan Timeout = TimeSpan.FromSeconds(10); 
public static void RunWithTimeout(ThreadStart method) { 
    var thread = new Thread(method); 
    thread.Start(); 
    if (!thread.Join(Timeout)) { 
     thread.Abort(); 
     Assert.False(true, "Timeout!"); 
} 
+0

恐怕這不起作用 - 這是XUnit Fact屬性中的超時值已經在做的事情。手動執行此操作似乎並沒有解決問題 - 當Quality Center庫的調用阻止它的所有操作時出現 - 將調試程序連接到進程會顯示所有線程都被阻止/等待連接,因此您無法得到一個堆棧跟蹤(雖然我還沒有嘗試過Intellitrace,但看看是否有幫助)。 – Bittercoder 2010-07-19 04:02:04

+0

@Bittercoder:我不明白這怎麼可能。嘗試將線程設置爲STA或MTA。 – SLaks 2010-07-19 12:45:58

+1

確保您的測試在STA線程上執行,TDConnection對執行它的MTA線程反應不佳。 – 2010-07-19 20:18:11

相關問題