如何对锁定语句进行单元测试?

时间:2012-05-30 13:07:21

标签: c# unit-testing locking

我如何编写单元测试以确保获得锁定?

例如:

public void AddItem(object item)
{
    lock (_list)
    {
        _list.Add(item)
    }
}

有没有办法确保运行lock语句?

编辑:我不是要证明线程安全(我会假设),只是调用了lock()语句。

例如,我可以通过在new object()工厂函数中替换它来测试CreateObject()语句。

6 个答案:

答案 0 :(得分:8)

单元测试多个线程总是很棘手,应该小心处理。

在您的情况下,我不会费心测试lock关键字,原因与您不为new编写测试的原因相同。

Assert.IsNotNull(new object());

此外,您似乎将其封装为线程不安全的集合,以使其成为线程安全的。考虑使用 thread-safe collections

,而不是重新发明轮子

答案 1 :(得分:4)

与测试任何其他东西的方式相同:编写一个没有它的测试失败。换句话说,首先确定您编写锁的原因,并编写指定该原因的测试。我假设原因是线程安全:如果是,请编写多线程测试。如果是其他原因,请进行测试。

如果你真的,真的想测试调用锁而不是锁导致的行为,请封装:

public class MyLock : IDisposable
{
    private object _toLock;

    public MyLock(object toLock)
    {
        _toLock = toLock;
        Monitor.Enter(_toLock);
    }

    public virtual void Dispose()
    {
        Monitor.Exit(_toLock);
    }
}

当然,你也必须建立一个可模拟的工厂。似乎过度使用它,但也许它在你的背景下是有道理的。

答案 2 :(得分:3)

请参阅Jon Skeet对类似问题的回答:How to test if a thread is holding a lock on an object in C#?

  

我不相信有。你可以做的事情很糟糕   喜欢调用Monitor.Wait(监视器,0)并捕获   SynchronizationLockException,但这非常可怕(并且可以   理论上“捕获”另一个线程正在等待的脉冲)。   编辑:在.NET 4.5中,这可用于Monitor.IsEntered。

答案 3 :(得分:1)

如果您已经编写了Lock语句(它执行与System.Threading.Lock语句类似的操作),那么我可以看到您为什么要测试它。

在这种情况下,您需要有一个_list类,您已经为此类实现了.Add方法,如果您使用依赖注入注入IList来设置_list,这将更容易。您需要使用IList的虚拟实例来实现.Add()方法。

如果你有一个假的.Add()调用sleep一段时间(比如5秒),你可以测试一下,启动一个线程来调用.AddItem()方法,这个线程会锁定.Add ()通过.AddItem()方法调用,然后主线程可以在调用.AddItem方法之前等待3秒。

如果锁定工作,第二个线程将在执行.Add之前延迟2秒,如果锁定不起作用,它将直接调用。

这是混乱和非确定性的,所以如果你运行足够的时间(数百万),你将得到错误的结果。

答案 4 :(得分:0)

你需要一个小程序来模拟读写线程......

在一个新线程中创建10,000个项目并添加它们,而在另一个线程中读取然后再睡眠一段时间。

然后在主要等待两个线程退出,你应该根据测试添加的次数得到结果并且没有调用remove ...

例如当i%2 == 0然后删除而不是添加生成器线程...这也应该影响消费者线程......

请参阅How to wait for thread to finish with .NET?

答案 5 :(得分:0)

不确定单元测试锁是否是正确的方法,而是应该正确测试AddItem的功能。但是你可以做几件事:

1)使用反射获取_list的引用,将其锁定在测试中,然后尝试调用AddItem

2)添加internal方法进行测试,锁定_list并暂停一段合理的时间(2秒?)。如果您make your internals visible to your test assembly,您可以在一个线程上调用测试方法,并在另一个线程上调用AddItem。请记住,这不是万无一失的,因为从技术上讲,测试可能会因为某种原因而被阻止,足以让初始锁定到期。