TPL单元测试BufferBlock LinkTo TargetBlock

时间:2017-09-06 12:43:51

标签: c# unit-testing asynchronous tpl-dataflow bufferblock

我正在尝试为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();
        }
    }

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

var result = await _queue.EnqueueAsync(message);

返回&#39; true&#39;在异常被抛出之前。 如何编写测试EnqueueTest_UnknownMessageType以使其失败,因为抛出了异常?

我尝试过添加

[ExpectedException(typeof(ArgumentException))]

进行测试,但仍然通过

1 个答案:

答案 0 :(得分:0)

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

通过docs for DataflowBlock.SendAsync()阅读以下有关返回值的内容:

  

如果目标在调用SendAsync期间接受并使用提供的元素,则在从调用返回时,生成的Task<TResult>将完成,其Result属性将返回{{1} }}。如果目标在通话期间拒绝提供的元素,则在通过通话返回时,结果true将完成,其Task<TResult>属性将返回Result

false仅表示第一个块收到或拒绝了该消息。没有提及将后续块中的异常传播回原始Task

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

否则,如果您希望这是更大的数据流管道中的一个步骤,您可以注入一个BroadcastBlock<T>,您可以附加其余的&#34;快乐路径&#34;用于处理已知消息类型的管道以及仅接收未知消息类型的块,您可以在其中接收要通信的任何操作,并收到未知消息类型。