NSubstitute icon indicating copy to clipboard operation
NSubstitute copied to clipboard

Arg.AnyType() for help with matching generic calls

Open dtchepak opened this issue 5 years ago • 0 comments

From https://github.com/nsubstitute/NSubstitute/issues/152#issuecomment-739048514:

Stumbled upon this while attempting to validate a call into Microsoft.Extensions.Logging.ILogger.

The logger interface takes a T state, but the "public" APIs (i.e. common extension methods) do not expose this directly.

For example, consumer code calls it like this:

logger.Critical("A critical problem has occurred!");

This is translated into a call to the interface's method, which has this signature:

public void Log<TState>(
            LogLevel logLevel,
            EventId eventId,
            TState state,
            Exception exception,
            Func<TState, Exception, string> formatter)

The string parameter that represents the message in the original call is not passed directly into this method, but instead is wrapped in an internal type and passed as state. Thus, it is actually impossible to perform an assertion on ILogger, since you cannot specify the internal type without getting a compilation error.

I actually solved this before by creating an abstract TestableLogger that exposes a non-generic version of the base interface method and then redirecting the implementation to it, and then using .Received on top of that new method. Obviously, this is extremely convoluted.

I'd really appreciate if NSubstitute provided a way to specify Any<AnyType>() that would check for any generic argument on a given parameter.

dtchepak avatar Dec 05 '20 01:12 dtchepak