Ronak Doshi
Ronak Doshi

Reputation: 39

Verify method invocation with Expression giving exception

I am trying to use Moq's Verify method (to verify that a method was called) by using the Linq Expression methods Api.

Below are two unit tests. TestMethod1 is using a simple lambda expression which is working fine.

I want to achieve exactly the same as TestMethod1 in TestMethod2; but by using the Linq Expression methods Api. But when I run TestMethod2 it is giving exception:

No coercion expression is defined between types Castle.Proxies.ISomeInterfaceProxy and Moq.Mock.

Can anyone please tell me what I am doing wrong?

using System;  
using System.Linq.Expressions;  
using Microsoft.VisualStudio.TestTools.UnitTesting;  
using Moq;

namespace UnitTestProject1  
{
  [TestClass]  
  public class UnitTest2  
  {  
    public interface ISomeInterface  
    {  
        void DoSomething(string param1, string param2);  
    }  

    public class ImplementationClass 
    {
        private ISomeInterface _someInterface;
        public ImplementationClass(ISomeInterface someInterface)
        {
            _someInterface = someInterface;
        }

        public void Investigate(string param1, string param2)
        {
            _someInterface.DoSomething(param1, param2);
        }
    }

    [TestMethod]
    public void TestMethod1()
    {
        Mock<ISomeInterface> myMock = new Mock<ISomeInterface>();
        ImplementationClass myImplementationClass = new ImplementationClass(myMock.Object);

        string Arg1 = "Arg1";
        string Arg2 = "Arg2";
        myImplementationClass.Investigate(Arg1, Arg2);

        Expression<Action<ISomeInterface>> lambdaExpression = m => m.DoSomething(Arg1, Arg2);

        myMock.Verify(lambdaExpression);
    }

    [TestMethod]
    public void TestMethod2()
    {
        Mock<ISomeInterface> myMock = new Mock<ISomeInterface>();
        ImplementationClass myImplementationClass = new ImplementationClass(myMock.Object);

        string Arg1 = "Arg1";
        string Arg2 = "Arg2";
        myImplementationClass.Investigate(Arg1, Arg2);

        var methodInfo = myMock.Object.GetType().GetMethod("DoSomething");
        var call = Expression.Call(Expression.Constant(myMock.Object), methodInfo, Expression.Constant(Arg1), Expression.Constant(Arg2));

        Expression<Action<ISomeInterface>> expression = Expression.Lambda<Action<ISomeInterface>>(call, Expression.Parameter(typeof(ISomeInterface)));

        myMock.Verify(expression); // Exception comes from here.
    }
  }
}

Upvotes: 0

Views: 308

Answers (1)

Richardissimo
Richardissimo

Reputation: 5773

The first problem was that you can't use the .Object of a Mock as the source of the type, since it isn't the "right" type. The safest way is to use the interface itself as the source of the type.

The second problem was that you need to specify a parameter to the lambda expression, and that needs to be the thing that you call the method on; just like you do in Test 1 m => m.DoSomething.

As a bonus tip, I'd recommend using nameof() rather than hard-coded string names - it means that you would get compile-time errors if you make a typo, rather than run-time errors.

And I'm throwing in the 'Arrange Act Assert' pattern to help readability; which is particularly important since this way of doing it is much harder to read than a simple lambda expression, in-lined into the Verify method's parameter.

So the fixed version looks like this...

    [TestMethod]
    public void TestMethod2()
    {
        // Arrange.
        Mock<ISomeInterface> myMock = new Mock<ISomeInterface>();
        ImplementationClass myImplementationClass = new ImplementationClass(myMock.Object);

        string Arg1 = "Arg1";
        string Arg2 = "Arg2";

        // Act.
        myImplementationClass.Investigate(Arg1, Arg2);

        // Assert.
        var methodInfo = typeof(ISomeInterface).GetMethod(nameof(ISomeInterface.DoSomething));
        var parameter = Expression.Parameter(typeof(ISomeInterface), "m");
        var call = Expression.Call(parameter, methodInfo, Expression.Constant(Arg1), Expression.Constant(Arg2));
        Expression<Action<ISomeInterface>> expression = Expression.Lambda<Action<ISomeInterface>>(call, parameter);

        myMock.Verify(expression);
    }

Upvotes: 2

Related Questions