Модульный тестовый блок TPL 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();
        }
    }

Исключение ArgumentException правильно генерируется в SetMessagePriority, потому что "MessageType" равен MessageType.Unknown. Тем не менее, к моменту создания ArgumentException модульный тест EnqueueTest_UnknownMessageType успешно прошел, поскольку

var result = await _queue.EnqueueAsync(message);

возвращает true до того, как сгенерировано исключение. Как мне написать тест EnqueueTest_UnknownMessageType, чтобы он не выполнялся, потому что генерируется исключение?

Я пробовал добавлять

[ExpectedException(typeof(ArgumentException))]

к тесту, но он все еще проходит

1 ответ

Решение

Как отметил @JSteward, исключение, которое вы ожидаете увидеть, не будет частью Task которую вы ждете в EnqueueAsync() метод.

Читая документы для DataflowBlock.SendAsync() говорит следующее о возвращаемом значении:

Если цель принимает и использует предложенный элемент во время вызова SendAsync по возвращении из звонка Task<TResult> будет завершено, и его Result собственность вернется true, Если цель отклоняет предложенный элемент во время вызова, при возврате из вызова получается Task<TResult> будет завершено, и его Result собственность вернется false,

Task только передает, что сообщение было получено или отклонено первым блоком. Нет упоминания о распространении исключений из последующих блоков обратно в оригинал Task,

Если вы ищете раннюю проверку типа сообщения, вы можете сделать эту проверку прямо в EnqueueAsync() вызов, удалив этот блок из вашего потока данных.

В противном случае, если вы хотите, чтобы это был шаг в более крупном потоке данных, вы можете добавить BroadcastBlock<T> к которому вы можете присоединить остальную часть конвейера "счастливого пути" для обработки известных типов сообщений, а также блок, который принимает только неизвестные типы сообщений, где вы можете предпринять любое действие, которое вы хотели бы сообщить, был получен неизвестный тип сообщения.

Другие вопросы по тегам