adrianiftode / Moq.ILogger

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

Unable to cast object of type 'System.Linq.Expressions.MethodCallExpression1' to type 'System.Linq.Expressions.NewArrayExpression'. #10

Closed mikeu closed 2 years ago

mikeu commented 3 years ago

I started adding Moq.ILogger to my test project this afternoon, and so far am very happy with it, thank you! However, while updating one of my tests, I encountered the following exception:

  Message: 
Moq.VerifyLogUnexpectedException : Moq.ILogger found an unexpected exception.

Please open an issue at https://github.com/adrianiftode/Moq.ILogger/issues/new, provide the exception details and a sample code if possible.
Bellow will follow the unexpected exception details.

---- System.InvalidCastException : Unable to cast object of type 'System.Linq.Expressions.MethodCallExpression1' to type 'System.Linq.Expressions.NewArrayExpression'.

  Stack Trace: 
VerifyLogExtensions.Verify[T](Mock`1 loggerMock, Expression`1 expression, Nullable`1 times, Func`1 timesFunc, String failMessage)
VerifyLogExtensions.VerifyLog[T](Mock`1 loggerMock, Expression`1 expression)
TestMyMethod.It_does_what_it_should(String someValue) line 67
--- End of stack trace from previous location ---
----- Inner Stack Trace -----
VerifyLogExpression.get_HasExpectedMessageArgs()
VerifyLogExtensions.CompareMessages(String expectedMessageFormat, VerifyLogExpression verifyLogExpression, Object actualMessageValues)
<>c__DisplayClass7_0`1.<Is>b__0(Object argument, Type parameterType) line 172
MatchFactory.Matches(Object argument, Type parameterType) line 251
IMatcher.Matches(Object argument, Type parameterType) line 78
InvocationShape.IsMatch(Invocation invocation) line 132
WhereArrayIterator`1.MoveNext()
Mock.GetMatchingInvocationCount(Mock mock, ImmutablePopOnlyStack`1& parts, HashSet`1 visitedInnerMocks, List`1 invocationsToBeMarkedAsVerified) line 467
Mock.GetMatchingInvocationCount(Mock mock, LambdaExpression expression, List`1& invocationsToBeMarkedAsVerified) line 439
Mock.Verify(Mock mock, LambdaExpression expression, Times times, String failMessage) line 323
Mock`1.Verify(Expression`1 expression, String failMessage) line 764
VerifyLogExtensions.Verify[T](Mock`1 loggerMock, Expression`1 expression, Nullable`1 times, Func`1 timesFunc, String failMessage)

My intention was to allow the test to still pass if the order in which the parameters passed to the log statement changed. For example, switching the logged message from ("The {Foo} received {Bar}", foo, bar) to ("{Bar} was sent to the {Foo}", bar, foo) should not cause the test to fail.

To that end, I was attempting to grab the object[] array of params and verify that it contained both Foo and Bar, without caring about order.

Here is a sample of the test that led to the above exception:

public async Task It_does_what_it_should (string someValue)
{
    Bar someInstance = new();

    await sut.MyMethodAsync(someValue, someInstance);

    mockLogger.VerifyLog(m => m.LogWarning(
        "*{Foo}*{@Bar}*",
        It.Is<object[]>(oo => oo.Contains(someValue) && oo.Contains(someInstance))
    ));
}

This seems to be the same general problem as in #3, but with different source and target types for the cast. I can resolve it by switching the constant string passed as the first argument to It.IsAny<string>(), or It.Is<string>(s => conditions(s)), which is fine for my use case, but wanted to report the unexpected exception to you as requested!

I'm using v1.1.9, with Moq 4.16.1. Please let me know if there are any additional details that would help, or if there's something in my approach that you'd expect the library to accomplish better in another way.

adrianiftode commented 2 years ago

Thank you for using Moq.ILogger and for submitting this issue. This has been fixed in 1.1.10

mikeu commented 2 years ago

Thanks @adrianiftode for the great library and quick response! I can confirm that with version 1.1.10 installed my tests are now working as intended.