TPL 单元测试 BufferBlock LinkTo TargetBlock

TPL Unit Test BufferBlock LinkTo TargetBlock

我正在尝试为 TPL BufferBlock 创建单元测试并想测试是否抛出异常。但是,测试在抛出异常之前通过。

编辑

此外,这是一个漫长的 运行 过程,所以我不称之为完成。此过程一直运行到应用程序关闭

代码如下:

public class PriorityMessageQueue 
{
        private BufferBlock<MyMessage> _messageBufferBlock;
        private async Task<bool> Init()
        {
            var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount,
                BoundedCapacity = 1000
            };

            var prioritizeMessageBlock = new ActionBlock<MyMessage>(msg =>
            {
                try
                {
                    SetMessagePriority(msg);
                }
                catch (Exception)
                {
                    throw;
                }

            });

            _messageBufferBlock = new BufferBlock<MyMessage>(executionDataflowBlockOptions);
            _messageBufferBlock.LinkTo(prioritizeMessageBlock);
        }

        public async Task<bool> EnqueueAsync(MyMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message), "The  message object is NULL. Cannot enqueue a NULL object.");
            }

            return await _messageBufferBlock.SendAsync(message);
        }

        private void SetMessagePriority(MyMessage message)
        {
           if (message.MessageType.Equals(MessageType.Unknown))
           {
               throw new ArgumentException("The SCBA Message Type is 'Unknown'. Cannot set the Message Priority on an 'Unknown' message type.");
           }

           switch (message.MessageType)
           {
               case MessageType.Admin:                   
                   message.MessagePriority = MessagePriority.Admin;
                   break;
               case MessageType.AuthUser:
                   message.MessagePriority = MessagePriority.High;
                   break;                
               case MessageType.UnknownUser:
                   message.MessagePriority = MessagePriority.Normal;
                   break;                
               default:
                   message.MessagePriority = MessagePriority.Normal;
                   break;
           }
        }

}

这是测试代码

    [TestClass()]
    public class PriorityMessageQueueTests
    {
        private IPriorityMessageQueue _queue;

        [TestInitialize]
        public void Init()
        {
            IUnityContainer container = new UnityContainer();

            var logRepository = new Mock<ILogRepository>();

            container.RegisterInstance(logRepository.Object);

            _queue = new PriorityMessageQueue(logRepository.Object);
        }

        [TestCleanup]
        public void CleanUp()
        {
            _queue.Dispose();
        }

        [TestMethod()]
        [ExpectedException(typeof(ArgumentNullException))]
        public async Task EnqueueTest_NullMessage()
        {
            await _queue.EnqueueAsync(null);
        }

        [TestMethod()]
        public async Task EnqueueTest_UnknownMessageType()
        {
            var message = new MyMessage
            {
                Id = 1,
                Text = "Unit Test"
            };

            var result = await _queue.EnqueueAsync(message);

            Assert.AreEqual(true, result);
        }

        [TestMethod()]
        public void DequeueTest()
        {
            Assert.Fail();
        }

        [TestMethod()]
        public void GetNextInQueue()
        {
            Assert.Fail();
        }
    }

在 SetMessagePriority 中正确抛出 ArgumentException 异常,因为 'MessageType' 等于 MessageType.Unknown。但是,当抛出 ArgumentException 时,单元测试 EnqueueTest_UnknownMessageType 已成功通过,因为

var result = await _queue.EnqueueAsync(message);

returns 'true' 在抛出异常之前。 我如何编写测试 EnqueueTest_UnknownMessageType 以使其因抛出异常而失败?

我试过添加

[ExpectedException(typeof(ArgumentException))]

参加考试,但还是通过了

正如@JSteward 指出的那样,您期望看到的异常不会成为您在 EnqueueAsync() 方法中等待的 Task 的一部分。

通读 docs for DataflowBlock.SendAsync() 说明以下关于 return 值的内容:

If the target accepts and consumes the offered element during the call to SendAsync, upon return from the call the resulting Task<TResult> will be completed and its Result property will return true. If the target declines the offered element during the call, upon return from the call the resulting Task<TResult> will be completed and its Result property will return false.

Task 仅表示消息已被第一个块接收或拒绝。没有提到将异常从后续块传播回原始 Task.

如果您正在寻找消息类型的早期验证,您可以直接在 EnqueueAsync() 调用中进行检查,从数据流管道中删除该块。

否则,如果您希望它成为更大数据流管道中的一个步骤,您可以注入一个 BroadcastBlock<T>,您可以将其附加到 "happy path" 管道的其余部分以处理已知消息类型以及一个只接收未知消息类型的块,您可以在其中采取任何您想传达的操作来传达收到的未知消息类型。