如何对线程安全队列进行单元测试

本文关键字:单元测试 队列 安全 线程 | 更新日期: 2023-09-27 18:13:23

我需要一个符合这些要求的简单数据结构:

  • 它应该表现得像一个队列,
  • 所有的排队操作应该是原子的。

我对多线程的经验非常有限,但这是我想到的:

public class Tickets
{
    private ConcurrentQueue<uint> _tickets;
    public Tickets(uint from, uint to)
    {
        Initialize(from, to);
    }
    private readonly object _lock = new object();
    public void Initialize(uint from, uint to)
    {
        lock(_lock)
        {
            _tickets = new ConcurrentQueue<uint>();
            for (uint i = from; i <= to; i++)
            {
                _tickets.Enqueue(i);
            }
        }
    }
    public uint Dequeue()
    {
        uint number;
        if (_tickets.TryDequeue(out number))
        {
            return number;
        }
        throw new ArgumentException("Ticket queue empty!");
    }
}

第一个问题:这个代码可以吗?

第二个问题:我如何对这个类进行单元测试(例如,两个线程定期对具有元素(1,2,3,4,5,6)的队列执行脱队操作,第一个线程应该只得到奇数,第二个线程只得到偶数)?我试过了,但是断言没有执行:

[Test]
public void Test()
{
    var tickets = new Tickets(1, 4);
    var t1 = new Thread(() =>
                            {
                                Assert.AreEqual(1, tickets.Dequeue());
                                Thread.Sleep(100);
                                Assert.AreEqual(3, tickets.Dequeue());
                            });

    var t2 = new Thread(() =>
                            {
                                Assert.AreEqual(2, tickets.Dequeue());
                                Thread.Sleep(100);
                                Assert.AreEqual(4, tickets.Dequeue());
                            });
    t1.Start();
    t2.Start();
}

如何对线程安全队列进行单元测试

我会使用chess: http://research.microsoft.com/en-us/projects/chess

CHESS是一个在并发程序中查找和重现heisenbug的工具。CHESS反复运行并发测试,确保每次运行都采用不同的交错。如果交错导致错误,CHESS可以重现交错以改进调试。CHESS可用于托管程序和本机程序。

多线程和单元测试的问题是时间问题。当您尝试在单元测试中引入多个线程时,您将面临不可重现测试结果的风险,即测试有时通过,但有时不通过。

但是只是为了解释为什么你的断言可能没有执行,单元测试在线程之前完成。它需要等待线程完成,而不是把它们踢开然后继续。单元测试框架本身也可能不是线程安全的,或者不能从其他线程调用断言。

对不起,这不是一个解决方案,但我也不知道任何多线程代码的自动化测试解决方案。

参见:我应该如何对线程代码进行单元测试?