我目前工作的一些基於.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線程中執行一些操作?
所以當他們把它稱爲「質量中心」,他們只是被諷刺? – Gabe 2010-07-19 02:44:26
我們只是說我不是產品的粉絲 - 哦,對於產品中的肥皂或REST服務:) – Bittercoder 2010-07-19 04:09:34
我們在OTA/TDApiOle80上爲QC 10執行了數百次集成測試,沒有問題或阻塞。所以理論上你應該可以做同樣的事情。 您是否嘗試解決阻塞本身的下劃線問題。 也許最好理解它爲什麼會阻塞,而不是試圖解決問題。 – 2010-07-19 20:21:48