adrianiftode / Moq.ILogger

Easy verify ILogger Moq mocks
Apache License 2.0
67 stars 7 forks source link

Verfying an error was logged fails #16

Open menaheme opened 1 month ago

menaheme commented 1 month ago

Hi Thank you for this helpful project. I have been using it for a while, and the experience is very good.

Recently written a test that is supposed to make sure an error is logged when a conditions is met.

The error appears to be logged (stepping through with the debugger i see it) but VerifyLog(..) fails the test anyway.

The call to the log looks like this: private void Alert() { logger.LogError(50100, "the description of the error goes here"); }

and the verifylog assertion looks like this

Mock.Get(logger).VerifyLog(l => l.LogError(50100, It.IsAny<string>()), Times.Once(), "an error must be logged");

the test output is strange:

Message:  Moq.VerifyLogException : an error must be logged Expected invocation on the mock once, but was 0 times: l => l.LogError((EventId)50100, It.IsAny(), new[] { })

---- Moq.MockException : an error must be logged Expected invocation on the mock once, but was 0 times: logger => logger.Log(LogLevel.Error, 50100, It.Is((v, t) => True), It.IsAny(), (Func<It.IsAnyType, Exception, string>)It.IsAny())

Performed invocations:

Mock (logger):

  ILogger.Log<FormattedLogValues>(LogLevel.Information, 0, KeepAliveMonitor started., null, Func<FormattedLogValues, Exception, string>)
  ILogger.Log<FormattedLogValues>(LogLevel.Error, 50100, the description of the error goes here, null, Func<FormattedLogValues, Exception, string>)

Stack Trace:  VerifyLogExtensions.Verify[T](Mock1 loggerMock, Expression1 expression, Nullable1 times, Func1 timesFunc, String failMessage) VerifyLogExtensions.VerifyLog(Mock1 loggerMock, Expression1 expression, Times times, String failMessage) KeepAliveMonitorTest.Test_Alert_Fired(Int32 i) line 45 InvokeStub_KeepAliveMonitorTest.Test_Alert_Fired(Object, Span1) MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) ----- Inner Stack Trace ----- Mock.Verify(Mock mock, LambdaExpression expression, Times times, String failMessage) line 332 Mock1.Verify(Expression1 expression, Times times, String failMessage) line 770 VerifyLogExtensions.Verify[T](Mock1 loggerMock, Expression1 expression, Nullable1 times, Func`1 timesFunc, String failMessage)

why is the assertion failing the test ?

adrianiftode commented 1 month ago

Hi, thanks for logging the issue.

I am trying to reproduce in the following PR, but I am not able to do so.

The only difference I see between your output and the output of a failing test in that branch is the concrete type used by the ILogger generic one. In your case is FormattedLogValues which is a bit odd. Possible to provide more context, maybe the setupt of the Mock?

menaheme commented 1 month ago

Thanks for taking the time to look!

I will try and provide more details tomorrow

On Mon, 16 Sept 2024, 20:23 Adrian Iftode, @.***> wrote:

Hi, thanks for logging the issue.

I am trying to reproduce in the following PR, but I am not able to do so.

The only difference I see between your output and the output of a failing test in that branch https://ci.appveyor.com/project/adrianiftode/moq-ilogger/builds/50611739/tests is the concrete type used by the ILogger generic one. In your case is FormattedLogValues which is a bit odd. Possible to provide more context, maybe the setupt of the Mock?

— Reply to this email directly, view it on GitHub https://github.com/adrianiftode/Moq.ILogger/issues/16#issuecomment-2353495520, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABLOIH7XHYTDFK4APPL2U33ZW4HZRAVCNFSM6AAAAABOHSXR72VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNJTGQ4TKNJSGA . You are receiving this because you authored the thread.Message ID: @.***>

menaheme commented 1 month ago

firs of all , i am using the Microsoft provided dependency injection library in testing (too).

so, to create a logger that will be a Mock<> i defined simple a LoggingProvider class .

using Microsoft.Extensions.Logging;
using Moq;

namespace MarginSpiderTests
{
public class TestLoggingProvider : ILoggerProvider
{
private readonly ILogger mockLogger;

public TestLoggingProvider()

{ mockLogger = Mock.Of<ILogger>(); }
public ILogger CreateLogger(string categoryName)

{ return mockLogger; }
public void Dispose() { }
}
}

and plug it in the DI like this hostBuilder.Services.AddSingleton<ILoggerProvider, TestLoggingProvider>();

and the test method looks like this:

[Fact]
public void Test_Alert_Not_Fired()
{
var keepAliveMonitor = host.Services.GetRequiredService<KeepAliveMonitor>(); 
var logger = host.Services.GetRequiredService<ILoggerProvider>().CreateLogger(nameof(KeepAliveMonitorTest)); 
keepAliveMonitor.StartMonitoring(0, 120);
Mock.Get(logger).VerifyLog(l => l.LogError(50100, It.IsAny<string>()), Times.Once(), "an error should be logged"); 
}
adrianiftode commented 1 month ago

Do you have tests that pass?