2010-07-19 42 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

相关问题