多线程单元测试

时间:2015-06-02 08:48:06

标签: 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()正在调用我想要测试的实际方法。

我创建了一个委托,一个事件和一个处理程序:

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”但没有“转换完成”。

我错过了什么让这个工作?或者我应该使用不同的方法吗?

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

2 个答案:

答案 0 :(得分:2)

良好的单元测试的一个特性是它需要是可重复的。每次运行时,都应该像以前一样运行。使用线程这是不可能的。例如,测试可能正常运行999次,但遇到死锁1次。这意味着该线程不仅无用,而且让您错误地确信您的代码实际上没有死锁。

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

模拟线程

提取掉线程代码并将其替换为可在测试中模拟的抽象。这样,单元测试代码将模拟多个线程,而不会将线程本身作为问题。但是这需要你知道线程可以通过你的代码的所有可能的路径,使它对任何复杂的事情都没用。

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

耐力测试

将测试设计为运行很长一段时间,产生新线程并始终调用代码。如果它运行几个小时而没有死锁,那么你就可以确信没有死锁。这不能作为普通测试套件的一部分运行,也不能让您100%放心。但它比尝试枚举线程可以交互的所有可能方式更实际。

答案 1 :(得分:0)

正如所建议我改变了方法。我现在正在使用:

document.getElementById(element).value

这个单元测试正在做我需要的:在不同的线程中调用我的转换方法。它已经证明了它的用途,因为我检测到我使用的字典不是线程安全的。我修复了它,现在我确信新库是线程安全的。

感谢大家的帮助和建议。