Ответ
Для тестирования зависимостей, реализующих интерфейс IConsumer<T>, используйте библиотеки для мокинга (Moq, NSubstitute) и проверяйте взаимодействие с ними в соответствии с контрактом.
Пример теста с Moq:
// Тестируемый сервис, зависящий от IConsumer<Order>
public class OrderProcessor
{
private readonly IConsumer<Order> _consumer;
public OrderProcessor(IConsumer<Order> consumer)
=> _consumer = consumer;
public void Process(Order order)
=> _consumer.Consume(order);
}
// Тест
[Test]
public void Process_ShouldCallConsumerExactlyOnce_WithCorrectOrder()
{
// Arrange
var mockConsumer = new Mock<IConsumer<Order>>();
var processor = new OrderProcessor(mockConsumer.Object);
var testOrder = new Order { Id = 123 };
// Act
processor.Process(testOrder);
// Assert
mockConsumer.Verify(
c => c.Consume(It.Is<Order>(o => o.Id == testOrder.Id)),
Times.Once
);
}
Ключевые аспекты тестирования Consumer:
- Изоляция: Mock заменяет реальную реализацию
IConsumer<T>, позволяя тестировать только поведение класса, который его использует. - Проверка вызовов: Убедитесь, что метод
Consumeвызывается ожидаемое количество раз (Times.Once,Times.Never). - Проверка аргументов: Используйте
It.Is<T>()для точной проверки переданных данных. - Тестирование исключений: Можно настроить mock на выброс исключения и проверить реакцию основного кода.
// Пример теста на обработку исключения от Consumer
[Test]
public void Process_ShouldLogError_WhenConsumerThrows()
{
var mockConsumer = new Mock<IConsumer<Order>>();
mockConsumer.Setup(c => c.Consume(It.IsAny<Order>()))
.Throws(new InvalidOperationException("Queue is full"));
var mockLogger = new Mock<ILogger<OrderProcessor>>();
var processor = new OrderProcessor(mockConsumer.Object, mockLogger.Object);
Assert.Throws<InvalidOperationException>(() => processor.Process(new Order()));
mockLogger.Verify(l => l.LogError(It.IsAny<string>()), Times.Once);
}