在具有许多子元素的元素上,Backgroundworker 中的测试执行突然结束

18
我的一般设置:我们编写了一个小型GUI的Excel导入程序,允许非程序员使用"Button.Click"等命令编写和执行GUI测试。底层框架是TestStack.White。导入Excel文件和其他用户交互后,测试将在System.ComponentModel.BackgroundWorker内部开始,只要我不查看(甚至与之交互)包含大量子元素的元素,它就可以正常工作。
但是,一旦我与具有许多元素的TestStack.White.UIItems.WindowItems.Window或TestStack.White.UIItems.UIItemContainer进行交互,测试执行就会结束。
通过交互,我指的是从简单的东西像非空检查或分配到本地变量,到请求其子计数等等。以下是一些终止测试执行的示例: 1)

if(theElement != null){ //everything after this line does not happen. The operator doesn't seem to be overloaded
   doStuff(); //it never reaches this point
}

2)

UIItemContainer pointOfInterest = theElement; //everything after this line does not happen

3)

System.Diagnostics.Debug.WriteLine("AmountOfElements: " + UIAnchor.Items.Count); //the output doesn't come. everything after this line does not happen

在没有数百元素的 Windows 中,所有三个示例都能正常工作。
通过很多元素,我的意思是例如一个内部有 ScrollView 的 Window,其中包含一个带有几十甚至数百条目的表格,每个条目由3-4列文本或复选框之类的内容组成。
Backgroundworkers RunWorkerCompleted 和 Disposed 都没有被调用。我根本没有得到任何异常,即使有故意放置的 try/catch 块也一样。调试器到达导致问题的那一行后就停止了。即使等待1小时,什么也不会发生。
相反,我只得到了几个不同的“线程 {一些十六进制 id} 已使用代码 259(0x103)退出。” 在 Visual Studio 的输出窗口中,这是来自我上次的测试执行:
The thread 0x830 has exited with code 259 (0x103).
The thread 0xfc0 has exited with code 259 (0x103).
The thread 0xc04 has exited with code 259 (0x103).

据我理解这条信息的意思是,线程仍然在运行。https://dev59.com/2mEh5IYBdhLWcg3wbjLc#22395548 如果我进入调试器检查导致错误的元素内容,我会发现所有在Items(具有子元素的列表)之后的元素都超时了,包括Items本身。
此外,问题不应该是主线程结束了,因为GUI仍然正常运行,就像在这个帖子中一样:Trying to step through BackgroundWorker code in debug but program ends unexpectedly
有人有什么想法或者如何解决这个问题吗?
这是我启动应用程序的方式:
Application app = TestStack.White.Application.Launch(pathToExeFile);
context.setApp(app); //context is a class with static variables to eas the access to all kind of stuff, so that i access it without having 20 parameters in every method (e.g. Button.Click())

接下来,用户设置他想要测试的窗口(可能是模态窗口,也可能不是 - 但在没有数百个元素的窗口中它能够工作):

foreach (Window win in context.getApp().GetWindows()) {
      System.Diagnostics.Debug.WriteLine("###SelectWindow: " + win.Name + " # " + win.PrimaryIdentification + " # " + win.Title);

      if (win.Name.Equals(nameOfWindowToTest)) {
        System.Diagnostics.Debug.WriteLine("###SelectWindow: gefunden");
        context.UIAnchor = win;
        System.Diagnostics.Debug.WriteLine("####SelectWindow: Anz Items: " + context.UIAnchor.Items.Count); //this gets called, but is the very last thing the thread does
        return null; //does not happen
      }
    }

context.UIAnchor是上面提到的元素。然后调用用户设置的方法(例如Button.Click)。有趣的是,context.UIAnchor = win并且items.count的输出有效。

更新:如果在关闭测试程序之前关闭要测试的应用程序,则会出现ElementNotAvaiableException。因此线程不应完全死亡。


如果我必须猜测,当你到达这一行时,UIItemContainer pointOfInterest = theElement;尽管theElement(可能)仍然为null,但是它是另一种数据类型而不是UIItemContainer,这就导致了问题。你是否尝试在那部分周围加上一个if条件判断语句?if (theElement is UIItemContainer) - Thomas
即使由于某些原因它仍然为空,[非]空检查也无法工作。:'( - CAA
最近我遇到了一个问题,即BackgroundWorker.DoWork中的异常在Visual Studio中没有显示,工作线程就消失了。你尝试过在抛出异常时打断点吗?我发现我的代码中缺少了Invoke,修复后问题得到了解决。 - Stephan B
@CAA 请添加初始化"theElement" 或者excel元素的代码。我认为你的程序仅加载要显示的项。所以与这些元素的交互会导致你的程序加载其余部分。 - Old Fox
@OldFox 我已经添加了我如何设置“theElement”的内容。Excel的东西在应用程序启动之前就被加载了 - 所以不可能出现像竞争条件这样的问题。 - CAA
2个回答

5

回答您上面的评论,我认为您的BackgroundWorker抛出了一个没有显示的异常——可能是因为这个Bug / Feature的原因。

运行这个小片段,直到你在调试/异常对话框中标记“Thrown”才会显示未处理的异常。

Public Class Form1

    Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        For I As Integer = 0 To 100
            BackgroundWorker1.ReportProgress(I)
            Threading.Thread.Sleep(25)
            If I = 50 Then Throw (New NullReferenceException)
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        BackgroundWorker1.RunWorkerAsync()
    End Sub

    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        ProgressBar1.Value = 0
    End Sub
End Class

(对于VB感到抱歉,适用于任何CLR)

示例显示(单击按钮后)一个ProgressBar填充到50%,然后停止,没有运行BackgroundWorker,没有Done事件。进入Throw只是退出该方法。

编辑:我的第一个示例错过了RunWorkerCompleted事件,现在正在触发,因此这可能与您的问题完全无关,对于噪音感到抱歉。


没有问题。即使对我来说没有用处,下一个有类似问题的人可能会在这个帖子中找到答案。 - CAA
伟大的链接,指向关于Obscura和Windows知识的史诗巨著。 - JJS

1
如果您在app.config中切换到传统的异常处理模式,会发生什么?
<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
  </runtime>
</configuration>

很遗憾,这并没有改变任何行为。在Visual Studio的任何窗口中也没有额外的异常消息或输出。 :/ - CAA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接