This is my controller:
public class BlogController : Controller
{
private IDAO _blogDAO;
private readonly ILogger _
I have created a package, Moq.ILogger, to make testing ILogger extensions much easier.
You can actually use something like the following which is more close to your actual code.
loggerMock.VerifyLog(c => c.LogInformation(
"Index page say hello",
It.IsAny
Not only it is easier to write new tests, but also the maintenance is with no costs.
The repo can be found here and there is a nuget package too (Install-Package ILogger.Moq
).
I explained it also with a real-life example on my blog.
In short, let's say if you have the following code:
public class PaymentsProcessor
{
private readonly IOrdersRepository _ordersRepository;
private readonly IPaymentService _paymentService;
private readonly ILogger _logger;
public PaymentsProcessor(IOrdersRepository ordersRepository,
IPaymentService paymentService,
ILogger logger)
{
_ordersRepository = ordersRepository;
_paymentService = paymentService;
_logger = logger;
}
public async Task ProcessOutstandingOrders()
{
var outstandingOrders = await _ordersRepository.GetOutstandingOrders();
foreach (var order in outstandingOrders)
{
try
{
var paymentTransaction = await _paymentService.CompletePayment(order);
_logger.LogInformation("Order with {orderReference} was paid {at} by {customerEmail}, having {transactionId}",
order.OrderReference,
paymentTransaction.CreateOn,
order.CustomerEmail,
paymentTransaction.TransactionId);
}
catch (Exception e)
{
_logger.LogWarning(e, "An exception occurred while completing the payment for {orderReference}",
order.OrderReference);
}
}
_logger.LogInformation("A batch of {0} outstanding orders was completed", outstandingOrders.Count);
}
}
You could then write some tests like
[Fact]
public async Task Processing_outstanding_orders_logs_batch_size()
{
// Arrange
var ordersRepositoryMock = new Mock();
ordersRepositoryMock.Setup(c => c.GetOutstandingOrders())
.ReturnsAsync(GenerateOutstandingOrders(100));
var paymentServiceMock = new Mock();
paymentServiceMock
.Setup(c => c.CompletePayment(It.IsAny()))
.ReturnsAsync((Order order) => new PaymentTransaction
{
TransactionId = $"TRX-{order.OrderReference}"
});
var loggerMock = new Mock>();
var sut = new PaymentsProcessor(ordersRepositoryMock.Object, paymentServiceMock.Object, loggerMock.Object);
// Act
await sut.ProcessOutstandingOrders();
// Assert
loggerMock.VerifyLog(c => c.LogInformation("A batch of {0} outstanding orders was completed", 100));
}
[Fact]
public async Task Processing_outstanding_orders_logs_order_and_transaction_data_for_each_completed_payment()
{
// Arrange
var ordersRepositoryMock = new Mock();
ordersRepositoryMock.Setup(c => c.GetOutstandingOrders())
.ReturnsAsync(GenerateOutstandingOrders(100));
var paymentServiceMock = new Mock();
paymentServiceMock
.Setup(c => c.CompletePayment(It.IsAny()))
.ReturnsAsync((Order order) => new PaymentTransaction
{
TransactionId = $"TRX-{order.OrderReference}"
});
var loggerMock = new Mock>();
var sut = new PaymentsProcessor(ordersRepositoryMock.Object, paymentServiceMock.Object, loggerMock.Object);
// Act
await sut.ProcessOutstandingOrders();
// Assert
loggerMock.VerifyLog(logger => logger.LogInformation("Order with {orderReference} was paid {at} by {customerEmail}, having {transactionId}",
It.Is(orderReference => orderReference.StartsWith("Reference")),
It.IsAny(),
It.Is(customerEmail => customerEmail.Contains("@")),
It.Is(transactionId => transactionId.StartsWith("TRX"))),
Times.Exactly(100));
}
[Fact]
public async Task Processing_outstanding_orders_logs_a_warning_when_payment_fails()
{
// Arrange
var ordersRepositoryMock = new Mock();
ordersRepositoryMock.Setup(c => c.GetOutstandingOrders())
.ReturnsAsync(GenerateOutstandingOrders(2));
var paymentServiceMock = new Mock();
paymentServiceMock
.SetupSequence(c => c.CompletePayment(It.IsAny()))
.ReturnsAsync(new PaymentTransaction
{
TransactionId = "TRX-1",
CreateOn = DateTime.Now.AddMinutes(-new Random().Next(100)),
})
.Throws(new Exception("Payment exception"));
var loggerMock = new Mock>();
var sut = new PaymentsProcessor(ordersRepositoryMock.Object, paymentServiceMock.Object, loggerMock.Object);
// Act
await sut.ProcessOutstandingOrders();
// Assert
loggerMock.VerifyLog(c => c.LogWarning(
It.Is(paymentException => paymentException.Message.Contains("Payment exception")),
"*exception*Reference 2"));
}