Проверьте вызов метода с выражением, дающим исключение - PullRequest
0 голосов
/ 27 июня 2018

Я пытаюсь использовать метод Moq Verify (чтобы убедиться, что метод был вызван), используя методы выражения Linq Api .

Ниже приведены два модульных теста. TestMethod1 использует простое лямбда-выражение, которое работает нормально.

Я хочу добиться того же, что и TestMethod1 в TestMethod2; но с помощью методов выражения Linq Api. Но когда я запускаю TestMethod2 , это дает исключение:

Не определено выражение приведения между типами Castle.Proxies.ISomeInterfaceProxy и Moq.Mock.

Может кто-нибудь сказать, пожалуйста, что я делаю не так?

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.
    }
  }
}

1 Ответ

0 голосов
/ 29 июня 2018

Первая проблема состояла в том, что вы не можете использовать .Object Mock в качестве источника типа, так как это не "правильный" тип. Самый безопасный способ - использовать сам интерфейс в качестве источника типа.

Вторая проблема заключалась в том, что вам нужно указать параметр для лямбда-выражения, и это должно быть то, для чего вы вызываете метод; так же, как вы делаете в тесте 1 m => m.DoSomething.

В качестве бонуса я бы рекомендовал использовать nameof() вместо жестко закодированных имен строк - это означает, что вы получите ошибки времени компиляции, если сделаете опечатку, а не ошибки времени выполнения.

И я добавляю шаблон 'Arrange Act Assert', чтобы улучшить читаемость; что особенно важно, поскольку этот способ намного сложнее для чтения, чем простое лямбда-выражение, встроенное в параметр метода Verify.

Так что исправленная версия выглядит так ...

    [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);
    }
...