c# - 多线程单元测试

标签 c# multithreading unit-testing

我有一个 C# 方法,将使用不同的线程多次调用。 所以我想创建一个单元测试来在多个线程上测试这个方法,但我不确定我做得对不对。

这是我没有线程的单元测试:

    [TestMethod]
    public void FromLocalPoints()
    {
        var projectedCoordinates = this.ConvertFromLocalPoints();
        foreach (var projectedCoordinate in projectedCoordinates)
        {
            Debug.Write(projectedCoordinate.X);
            Debug.Write("; ");
            Debug.WriteLine(projectedCoordinate.Y);
        }
    }

this.ConvertFromLocalPoints() 正在调用我要测试的实际方法。

我已经创建了一个委托(delegate)、一个事件和一个处理程序:

public delegate void ReprojectCompleteHandler(IEnumerable<Coordinate> projectedCoordinates);
public event ReprojectCompleteHandler ReprojectCompleteEvent;
private void ReprojectHandler(IEnumerable<Coordinate> projectedCoordinates)
{
        Debug.WriteLine("Conversion is complete");
}

在我的 TestSetup 中,我收听我的事件:

    [TestInitialize]
    public void TestSetup()
    {
        this.ReprojectCompleteEvent += this.ReprojectHandler;
    }

我的单元测试是:

    [TestMethod]
    public void FromLocalPointsThreaded()
    {
        // Call FromLocalPoints multiple times in separate threads to check if it is thread safe
        for (var i = 0; i < 10; i++)
        {
            var myThread = new Thread(this.ConvertFromLocalPointsThreaded);    
        }

        Debug.WriteLine("FromLocalPointsThreaded is done");
    }

    private void ConvertFromLocalPointsThreaded()
    {
        var projectedCoordinates = this.ConvertFromLocalPoints();

        // Send result to delegate/event:
        if (this.ReprojectCompleteEvent != null)
        {
            this.ReprojectCompleteEvent(projectedCoordinates);
        }
    }

当我运行这个单元测试时,我在输出中得到一次“FromLocalPointsThreaded is done”,但没有“Conversion is complete”。

我缺少什么才能让它正常工作?或者我应该使用不同的方法?

更新 我们目前正在切换进行实际转换的库。旧库不是线程安全的,因此我们添加了锁。新库应该是线程安全的,所以我想移除锁。但我需要一个单元测试来证明我们使用新库的方法确实是线程安全的。

最佳答案

好的单元测试的一个特性是它需要可重复。每次运行时,它应该以与以前相同的方式运行。这对于线程来说是不可能的。例如,测试可能正常运行 999 次,但遇到死锁 1 次。这意味着该线程不仅无用,而且会让您误以为您的代码实际上没有死锁。

为了测试线程安全,几乎没有其他方法可以实现:

模拟线程

提取线程代码并将其替换为可以在测试中模拟的抽象。这样,单元测试代码将模拟多个线程,而线程本身不会成为问题。但这需要您了解线程可以通过您的代码的所有可能路径,因此它对任何复杂的事情都毫无用处。

这也可以通过使用不可变数据结构和纯方法来帮助实现。然后,测试代码仅限于提供线程间同步的一小部分代码。

耐力测试

将测试设计为运行极长的时间段,始终生成新线程并调用代码。如果它运行了几个小时而没有死锁,那么您就可以确信没有死锁。这不能作为正常测试套件的一部分运行,也不能给您 100% 的信心。但这比尝试枚举线程交互的所有可能方式要实用得多。

关于c# - 多线程单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30591384/

相关文章:

c# - 在知道正确的数组长度之前,如何在 C# 中将字节数组初始化为 OUT 参数

c# - 在 csv 文件中查找重复项目

c# - 从 HTTP POST 获取查询字符串?

Linux内核: is vfs_write thread safe?

php - 在 PHP 中有多少个打开的文件?

c# - 显示 Unity3d 广告后跟 Application.LoadLevel (Application.loadedLevel);

c# - 显示Windows窗体时,控制台应用程序不接受输入

python多处理池超时

sql - 更改自动生成的序列

java - 在 JUnit 测试(java)中如何使用 Assertj 库检查数组的数组?