如何为线程不安全的集合编写单元测试

时间:2011-01-23 18:36:46

标签: c# multithreading unit-testing tdd thread-safety

我正在使用TDD方法编写双向链表。此集合类型不是线程安全的。为了实现ICollection接口,我的列表类必须具有多个公共属性(包括IsSynchronized和SyncRoot,它们用于提供使用线程安全的集合方式)。 这两个属性的代码非常简单:

public bool IsSynchronized { get { return false; } }

private readonly object _syncRoot = new object();
public object SyncRoot { get { return _syncRoot; } }

问题是如何为它编写正确的单元测试。此测试应检查正确的用法和错误使用。

2 个答案:

答案 0 :(得分:5)

  

我的列表类必须有几个公共属性(包括IsSynchronized和SyncRoot

没有。这可以追溯到.NET版本1,并被广泛认为是一个巨大的错误。它造成了一种虚假的线程安全感,让很多程序员陷入了困境。在所有情况下,这样的类实际上并不是线程安全的,迭代一个不是。它完全被删除在.NET 2.0泛型集合类中。并且您不应该实现ICollection,现代集合类应该是通用的并实现ICollection<T>。不幸的是,仍然需要实现IEnumerable,这是我们可能永远不会摆脱的遗产。您可以使用显式实现来实现它,这些方法不公开。

次要考虑因素是实施ICollection&lt;&gt;是个好主意。链表使像Count这样的成员贵,它本质上是O(n)。您需要分别跟踪列表中的元素数量,使其为O(1)。 .NET LinkedList&lt;&gt; class,也是一个双向链表列表集合,确实这样做。

答案 1 :(得分:0)

我会说这属于而不是你的责任SyncRoot属性是存在的,以防有人使用您的集合类想要同步读/写,提供一个方便的对象来锁定 - 仅此而已。 (事实上​​,这个属性的目的被广泛误解;属性本身通常被认为是无用的,如Hans has pointed out。)

如果您确实认为您有足够的理由来实现此接口,那么同步完全超出您的类型本身的范围(正如您通过IsSynchronized属性返回{{1 }});因此,它不应该真的需要在你的最后进行单元测试。

事实上,我认为false接口的实现者很容易忽略ICollection属性(将其设置为SyncRoot)。那应该告诉你一些事情。

对于单元测试,您只需验证null属性不是SyncRoot