Настройте макет для метода, используя Expression - PullRequest
1 голос
/ 08 ноября 2019

Я пытаюсь установить ложное возвращаемое значение для метода. Я знаю классический способ сделать это, но я хочу сделать это, явно создав объекты Expression. Вот что я попробовал до сих пор:

using Moq;
using NUnit.Framework;
using System;
using System.Linq.Expressions;

namespace MoqTest
{
    public interface IBlah
    {
        string DoStuff(string x);
    }

    public class SomeProgram
    {
        static void Main(string[] args)
        {
            Mock<IBlah> m = new Mock<IBlah>(MockBehavior.Strict);

            //I want to do the equivalent of this:
            //m.Setup(a => a.DoStuff(It.IsAny<string>())).Returns("mocked!");

            var method = typeof(IBlah).GetMethod("DoStuff", new Type[] { typeof(string) });
            ParameterExpression parameterForDoStuff = Expression.Parameter(typeof(string), "x");
            ParameterExpression thisParameter = Expression.Parameter(typeof(IBlah), "someIBlahInstance");
            MethodCallExpression methodCall = Expression.Call(thisParameter, method, new[] { parameterForDoStuff });
            Expression<Func<IBlah, string>> lambdaExpression = Expression.Lambda<Func<IBlah, string>>(methodCall, new ParameterExpression[] { parameterForDoStuff });
            //above line fails: Unhandled Exception: System.ArgumentException: ParameterExpression of type 'System.String' cannot be used for delegate parameter of type 'MoqTest.IBlah'

            m.Setup(lambdaExpression).Returns("mocked!");

            Assert.AreEqual("mocked!", m.Object.DoStuff(string.Empty));
        }
    }
}

Как вы можете видеть, я запутался, когда дело доходит до lambdaExpression - я должен создать такой, который представляет Func<string,string> (для IBlah. Метод DoStuff), или я должен создать Func<IBlah,string> (представляющий лямбда-параметр для метода Mock.Setup)? Я поместил эквивалентную настройку, которую я хочу сделать, в комментарии в коде.

Ответы [ 2 ]

1 голос
/ 08 ноября 2019

Вы должны создать Expression<Func<IBlah, string>>, представляющий параметр выражения для метода Mock.Setup.

Это означает, что должен быть только один параметр выражения.

Кроме того, при построениитребуемое выражение, It.IsAny<T>() - это общий вызов статического метода для статического класса Moq.It.

Просмотрите комментарии, чтобы увидеть, как этот статический вызов встроен в выражение с помощью отражения.

[TestClass]
public class MoqExpressionTests {
    [TestMethod]
    public void Should_Build_Moq_Expression() {
        //Arrange
        //I want to do the equivalent of this:
        //m.Setup(a => a.DoStuff(It.IsAny<string>())).Returns("mocked!");
        var doStuff = typeof(IBlah).GetMethod("DoStuff", new Type[] { typeof(string) });
        var isAnyOfString = typeof(It).GetMethod("IsAny").MakeGenericMethod(typeof(string));

        // IBlah x =>
        ParameterExpression parameter = Expression.Parameter(typeof(IBlah), "x");
        // It.IsAny<string>()            
        var arg = Expression.Call(isAnyOfString);
        // IBlah x => x.DoStuff(It.IsAny<string>())           
        MethodCallExpression body = Expression.Call(parameter, doStuff, new[] { arg });
        //Func<IBlah, string> = IBlah x => x.DoStuff(It.IsAny<string>())
        Expression<Func<IBlah, string>> expression = 
            Expression.Lambda<Func<IBlah, string>>(body, parameter);

        var expected = "mocked!";
        Mock<IBlah> m = new Mock<IBlah>(MockBehavior.Strict);
        m.Setup(expression).Returns(expected);
        var subject = m.Object;

        //Act
        var actual = subject.DoStuff(string.Empty);

        //Assert
        Assert.AreEqual(expected, actual);
    }

    public interface IBlah {
        string DoStuff(string x);
    }
}
0 голосов
/ 08 ноября 2019
  1. вы не можете использовать строковый параметр для It.IsAny, нужно использовать MethodCallExpression
  2. для параметра lambdaExpression Expression второй параметр должен быть thisParameter.

    public class SomeProgram
    {
        static void Main(string[] args)
        {
            Mock<IBlah> m = new Mock<IBlah>(MockBehavior.Strict);
    
            //I want to do the equivalent of this:
            //m.Setup(a => a.DoStuff(It.IsAny<string>())).Returns("mocked!");
    
            var method = typeof(IBlah).GetMethod("DoStuff", new Type[] { typeof(string) });
            MethodInfo genericIsAnyMethodInfo =
                typeof(It).GetMethods().Single(e => e.Name == "IsAny").MakeGenericMethod(typeof(string));
            MethodCallExpression parameterForDoStuff = Expression.Call(genericIsAnyMethodInfo);
            //ParameterExpression parameterForDoStuff = Expression.Parameter(typeof(string), "x");
            ParameterExpression thisParameter = Expression.Parameter(typeof(IBlah), "someIBlahInstance");
            MethodCallExpression methodCall = Expression.Call(thisParameter, method, new[] { parameterForDoStuff });
            Expression<Func<IBlah, string>> lambdaExpression = Expression.Lambda<Func<IBlah, string>>(methodCall, thisParameter);
            //above line fails: Unhandled Exception: System.ArgumentException: ParameterExpression of type 'System.String' cannot be used for delegate parameter of type 'MoqTest.IBlah'
    
            m.Setup(lambdaExpression).Returns("mocked!");
    
            Assert.AreEqual("mocked!", m.Object.DoStuff(string.Empty));
        }
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...