1

I am trying to mock a Func<Tin, Tout> using Moq and verify that it is being called (invoked)

the code I currently have is:

var handlers = new List<ICallBridgeHandler>();
var stationIdReader = new Mock<IStationIdReader>();
var loggerCreator = new Mock<Func<Type, ILogger>>();
loggerCreator.Setup(x => x.Invoke(typeof(Service))).Returns<ILogger>(null);

loggerCreator.Verify(x => x.Invoke(It.IsAny<Type>()), Times.Never);
var sut = new Service(stationIdReader.Object, handlers, loggerCreator.Object);
loggerCreator.Verify(x => x.Invoke(typeof(Service)), Times.Once);
Assert.IsNotNull(sut);

but this is blowing up with the exception:

Result StackTrace:  
at Moq.ExpressionExtensions.GetCallInfo(LambdaExpression expression, Mock mock)
at Moq.Mock.<>c__DisplayClass1c`2.<Setup>b__1b()
at Moq.PexProtector.Invoke[T](Func`1 function)
at Moq.Mock.Setup[T,TResult](Mock`1 mock, Expression`1 expression, Condition condition)
at Moq.Mock`1.Setup[TResult](Expression`1 expression)
at Tests.ConstructorRetrievesLoggerFromCreator() in ...

Result Message: 
Test method Tests.ConstructorRetrievesLoggerFromCreator threw exception: 
System.InvalidCastException: Unable to cast object of type
'System.Linq.Expressions.InstanceMethodCallExpressionN' to type
'System.Linq.Expressions.InvocationExpression'.

Can anyone help with this, I need to be able to check that the constructor calls the Func.

N.B. I tried to remove the setup step as I do not care about the return value for this test, and I get the same problem on the Verify call.

Obviously I could inject a concrete Func that returns a given value and interrogate that value in some way, however my Service class looks like:

public class Service 
{
    private readonly ILogger _logger;

    [ImportingConstructor]
    public Service([Import("GetLogger")]Func<Type, ILogger> loggerCreator)
    {
        if (loggerCreator == null)
            throw new ArgumentNullException(nameof(loggerCreator));

        _logger = loggerCreator.Invoke(GetType());
    }
}

So without changing my class I cannot see the member variable _logger so I have no way to verify that loggerCreator has been invoked, and that is what I want to verify.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
MikeW
  • 1,568
  • 2
  • 19
  • 39
  • I'm not sure you can moq delegates. – Nkosi Apr 22 '16 at 09:50
  • The other question does not show how to verify that the Func is called, it allows you to inject a Func that returns a mocked object, which by interrogating this returned value can implicitly verify that the Func is called, but (as explained in my edits) as I do not expose the returned value of the Func from my Service class I cannot use this approach with modifying my code. – MikeW Apr 22 '16 at 10:35

1 Answers1

1

There is no need to mock the function. Create a Func variable and keep a counter in there to keep track.

[TestMethod]
public void Func_Should_Be_Invoked_Once() {
    //Arrange
    var handlers = new List<ICallBridgeHandler>();
    var stationIdReader = new Mock<IStationIdReader>();
    var mockLogger = new Mock<ILogger>();
    int loggerCreaterInvokeCalls = 0;
    Func<Type, ILogger> loggerCreator = (type) => {
        loggerCreaterInvokeCalls++;
        return mockLogger.Object;
    };
    //Act
    var sut = new Service(stationIdReader.Object, handlers, loggerCreator);
    //Assert
    Assert.IsNotNull(sut);
    Assert.AreEqual(1, loggerCreaterInvokeCalls);
}

Reference: Using Moq to Mock a Func<> constructor parameter and Verify it was called twice

Community
  • 1
  • 1
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • great answer Moq is irrelevant, a manually constructed spy is best option, thanks @NKosi – MikeW Apr 22 '16 at 10:42
  • @MikeW, no problem. You were on the right track with injecting a concrete `Func` and would have gotten to the right solution eventually. – Nkosi Apr 22 '16 at 10:52