我有一个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的方法真的是线程安全的。
答案 0 :(得分:2)
良好的单元测试的一个特性是它需要是可重复的。每次运行时,都应该像以前一样运行。使用线程这是不可能的。例如,测试可能正常运行999次,但遇到死锁1次。这意味着该线程不仅无用,而且让您错误地确信您的代码实际上没有死锁。
为了测试线程安全性,几乎没有其他方法可以实现它:
模拟线程
提取掉线程代码并将其替换为可在测试中模拟的抽象。这样,单元测试代码将模拟多个线程,而不会将线程本身作为问题。但是这需要你知道线程可以通过你的代码的所有可能的路径,使它对任何复杂的事情都没用。
使用不可变数据结构和纯方法也可以帮到这一点。然后,经过测试的代码仅限于在线程之间提供同步的一小部分代码。
耐力测试
将测试设计为运行很长一段时间,产生新线程并始终调用代码。如果它运行几个小时而没有死锁,那么你就可以确信没有死锁。这不能作为普通测试套件的一部分运行,也不能让您100%放心。但它比尝试枚举线程可以交互的所有可能方式更实际。
答案 1 :(得分:0)
正如所建议我改变了方法。我现在正在使用:
document.getElementById(element).value
这个单元测试正在做我需要的:在不同的线程中调用我的转换方法。它已经证明了它的用途,因为我检测到我使用的字典不是线程安全的。我修复了它,现在我确信新库是线程安全的。
感谢大家的帮助和建议。