简体   繁体   English

使用表达式为方法设置模拟

[英]Setup a mock for a method using Expression

I'm trying to setup a mocked return value for a method.我正在尝试为一个方法设置一个模拟的返回值。 I know the classic way of doing it, but I want to do it by creating Expression objects explicitly.我知道这样做的经典方式,但我想通过显式创建 Expression 对象来做到这一点。 Here is what I have tried so far:这是我到目前为止所尝试的:

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

As you can see, I'm confused when it comes to the lambdaExpression - should I be creating one that represents a Func<string,string> (for the IBlah.DoStuff method), or should I be creating a Func<IBlah,string> (representing the lambda parameter for the Mock.Setup method)?正如您所看到的,我对 lambdaExpression 感到困惑 - 我应该创建一个代表Func<string,string> (对于 IBlah.DoStuff 方法),还是应该创建一个Func<IBlah,string> (代表 Mock.Setup 方法的 lambda 参数)? I put the equivalent setup that I want to do in a comment in the code.我将我想做的等效设置放在代码的注释中。

You should be creating a Expression<Func<IBlah, string>> representing the expression parameter for the Mock.Setup method.您应该创建一个Expression<Func<IBlah, string>>表示Mock.Setup方法的表达式参数。

Which means that there should only be one parameter expression.这意味着应该只有一个参数表达式。

Also, in building the desired expression, It.IsAny<T>() is a generic static method call on the static class Moq.It .此外,在构建所需的表达式时, It.IsAny<T>()是对 static class Moq.It的通用 static 方法调用。

Review the comments to see how that static call is built into the expression using reflection.查看评论以了解 static 调用是如何使用反射内置到表达式中的。

[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);
    }
}
  1. you can no use a string parameter for It.IsAny, need use MethodCallExpression It.IsAny 不能使用字符串参数,需要使用 MethodCallExpression
  2. for the lambdaExpression Expression second parameter should be thisParameter.对于 lambdaExpression 表达式,第二个参数应该是 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)); } }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过 Setup 设置模拟属性会导致“表达式不是方法调用” - Setting mock property via Setup causes 'Expression is not a method invocation' 如何使用Mock设置从void方法返回值 - How to return a value from a void method using Mock setup 使用await调用方法时,模拟设置返回null - Mock setup returning null when the method is called using await 如何使用Moq模拟/设置具有IEnumerable输入参数的方法? - How to mock/setup a method with IEnumerable input parameters using Moq? 安装程序模拟重定向到重载方法 - Setup Mock to redirect to overloaded method 模拟表达参数到存储库方法 - Mock Expression Parameter to Repository Method 如何在使用Ninject时使用SetUp方法填充模拟数据库来模拟通用的Get方法? - How to mock a generic Get method when using Ninject and use a SetUp method to populate the mocked database? 如何模拟设置方法以返回不同的值 - How to mock setup a method to return different value 是否需要调用在 Mock object 上设置方法,我们要验证它是否使用 Moq 调用? - Is a call needed to Setup a method on Mock object that we want to Verify that it is called using Moq? 使用 lambda 表达式作为输入参数的 xUnit 模拟方法 - xUnit mock method with lambda expression as input parameter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM