在单元测试中无法复制'跨线程操作无效'错误 - 我不明白

时间:2011-11-06 04:22:24

标签: c# .net multithreading unit-testing nunit

这是我的第一个Stack问题,如果我的格式或礼仪稍微偏离,请提前道歉。

我最近在从单独的线程与WinForms控件交互时设置了处理'cross-thread operation not valid' issues的模式。

我认为设置一个单元测试以隔离它并断言我的SynchronisationContext扩展修复了这个问题会很好,所以我创建了一个简单的测试表单,上面有一个按钮和一些名为'PerformClick()'的代码从另一个线程复制问题:

    [STAThread]
    static void Main()
    {           
        using (TestForm form = new TestForm())
        {
            Thread t1 = new Thread(() => Application.Run(form));
            Thread t2 = new Thread(() => form.buttonStart.PerformClick());
            form.Activated += (sender, args) => t2.Start();
            t1.Start();
            Thread.Sleep(1000); //Prevents form from being disposed before 'click' can occur from other thread.
        }                       
    }

测试表单实际上是一个空表单,上面有一个按钮。当我运行此代码时,我得到了预期的跨线程操作异常。

但是当我将代码放入NUnit测试时,不会发生异常。这是我的单元测试:

    [Test]
    public void PostToControl_AcrossThreads()
    {           
        //Notes: This code normally generates a cross-thread exception.
        //For some reason, when you run it in the scope of the unit test, the exception is not generated.
        using (TestForm form = new TestForm())
        {
            Thread t1 = new Thread(() => Application.Run(form));
            Thread t2 = new Thread(() => form.buttonStart.PerformClick());
            form.Activated += (sender, args) => t2.Start();
            t1.Start();
            Thread.Sleep(1000); //Prevents form from being disposed before 'click' can occur from other thread.
        }
    }

我意识到我不清楚为什么会这样,所以我把它扔给专家:-)

任何人都可以开导我吗?与单独运行表单相比,单元测试中发生的情况如此不同?

3 个答案:

答案 0 :(得分:3)

使用除PerformClick()之外的其他内容。例如form.buttonStart.Text = "This is my form";或更改职位等......

原因是,方法PerformClick()仅引发.NET事件Click。但是跨线程操作的问题是使用windows-message-loop。因此,如果你想“做问题”,你必须执行一些使用windows-message-loop的行动。

答案 1 :(得分:2)

此行为由属性控制:Control.CheckForIllegalCrossThreadCalls

默认情况下,只有在附加调试器时才会出现这种情况,这就是您所看到的行为。

答案 2 :(得分:0)

  

任何人都可以开导我吗?单位中发生的情况如此不同   测试与本机运行表单相比?

没有什么不同。

如果您需要在Nunit上检查异常,请更好地使用Exception Asserts。否则nunit不会为您显示例外情况。

如果你没有为异常做资产,至少放一个try catch块并记录异常,你也会在测试用例中得到相同的异常。