11

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

例如:

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

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

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

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

4

6 回答 6

9

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

在您的情况下,我不会打扰测试lock关键字,原因与您不为new.

Assert.IsNotNull(new object());

此外,您似乎将其封装为线程不安全的集合以使其成为线程安全的。与其重新发明轮子,不如考虑使用线程安全的集合

于 2012-05-30T13:16:39.933 回答
4

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

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

于 2012-06-01T04:57:24.157 回答
4

与测试任何其他事物的方式相同:编写一个没有它就失败的测试。换句话说,首先确定你写锁的原因,然后写一个测试来说明这个原因。我认为原因是线程安全:如果是这样,请编写多线程测试。如果是其他原因,请正确进行该测试。

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

public class MyLock : IDisposable
{
    private object _toLock;

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

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

当然,你也必须制作一个可模拟的工厂。对我来说似乎做得过火了,但在您的上下文中可能是有道理的。

于 2012-06-01T04:21:13.697 回答
1

如果您编写了 Lock 语句(它的作用类似于 System.Threading.Lock 语句),那么我可以理解您为什么要测试它。

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

如果你有一个虚拟的 .Add() 调用休眠一段时间(比如 5 秒),你可以通过启动一个线程来调用 .AddItem() 方法进行测试,这个线程将锁定 .Add() 调用通过 .AddItem() 方法,主线程可以在调用 .AddItem 方法之前等待 3 秒。

如果锁有效,第二个线程会在执行 .Add 之前延迟 2 秒,如果锁无效,它会立即调用。

这是混乱和不确定的,所以如果你运行足够多的时间(数百万次),你会得到一个错误的结果。

于 2012-05-30T13:37:21.683 回答
0

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

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

2) 添加一种internal测试方法,该方法可以锁定_list并暂停一段合理的时间(2 秒?)。如果您使您的内部结构对您的测试程序集可见,您可以在一个线程上调用测试方法并AddItem在另一个线程上调用。请记住,这不是万无一失的,因为从技术上讲,测试可能由于某种原因被阻塞足够长的时间,以使初始锁定到期。

于 2012-05-30T13:24:21.803 回答
0

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

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

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

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

请参阅如何等待线程完成 .NET?

于 2012-05-30T13:21:44.707 回答