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

C# 使用表达式为方法设置模拟,c#,linq,moq,C#,Linq,Moq,我正在尝试为方法设置模拟返回值。我知道这样做的经典方法,但我想通过显式创建表达式对象来实现。以下是我迄今为止所尝试的: using Moq; using NUnit.Framework; using System; using System.Linq.Expressions; namespace MoqTest { public interface IBlah { string DoStuff(string x); } public class

我正在尝试为方法设置模拟返回值。我知道这样做的经典方法,但我想通过显式创建表达式对象来实现。以下是我迄今为止所尝试的:

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));
        }
    }
}
使用Moq;
使用NUnit.Framework;
使用制度;
使用System.Linq.Expressions;
名称空间MoqTest
{
公共接口IBlah
{
字符串DoStuff(字符串x);
}
公共课程
{
静态void Main(字符串[]参数)
{
Mock m=新的Mock(MockBehavior.Strict);
//我想做类似的事情:
//m、 Setup(a=>a.DoStuff(It.IsAny()).Returns(“mocked!”);
var method=typeof(IBlah).GetMethod(“DoStuff”,新类型[]{typeof(string)});
ParameterExpression parameterForDoStuff=Expression.Parameter(typeof(string),“x”);
ParameterExpression thisParameter=Expression.Parameter(typeof(IBlah),“someiblaInstance”);
MethodCallExpression methodCall=Expression.Call(thisParameter,method,new[]{parameterForDoStuff});
表达式lambdaExpression=Expression.Lambda(methodCall,新参数Expression[]{parameterForDoStuff});
//上述行失败:未处理的异常:System.ArgumentException:类型为“System.String”的ParameterExpression不能用于类型为“MoqTest.IBlah”的委托参数
m、 安装程序(lambdaExpression)。返回(“mocked!”);
AreEqual(“mocked!”,m.Object.DoStuff(string.Empty));
}
}
}

正如您所看到的,当涉及lambdaExpression时,我感到困惑-我应该创建一个表示
Func
(对于IBlah.DoStuff方法)的表达式,还是应该创建一个
Func
(对于Mock.Setup方法,表示lambda参数)?我将要执行的等效设置放在代码的注释中。

您应该创建一个
表达式
,表示
Mock.setup
方法的表达式参数

这意味着应该只有一个参数表达式

另外,在构建所需的表达式时,
It.IsAny()
是对静态类
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);
    }
}
[TestClass]
公共类MoqExpressionTests{
[测试方法]
public void应该构建Moq表达式(){
//安排
//我想做类似的事情:
//m、 Setup(a=>a.DoStuff(It.IsAny()).Returns(“mocked!”);
var doStuff=typeof(IBlah).GetMethod(“doStuff”,新类型[]{typeof(string)});
var isAnyOfString=typeof(It).GetMethod(“IsAny”).MakeGenericMethod(typeof(string));
//伊布拉x=>
ParameterExpression参数=表达式参数(typeof(IBlah),“x”);
//It.IsAny()
var arg=Expression.Call(isAnyOfString);
//IBlah x=>x.DoStuff(It.IsAny())
MethodCallExpression body=Expression.Call(参数,doStuff,new[]{arg});
//Func=IBlah x=>x.DoStuff(It.IsAny())
表达式表达式=
表达式.Lambda(主体,参数);
var expected=“mocked!”;
Mock m=新的Mock(MockBehavior.Strict);
m、 设置(表达式)。返回(预期);
var subject=m.Object;
//表演
var-actual=subject.DoStuff(string.Empty);
//断言
断言.AreEqual(预期、实际);
}
公共接口IBlah{
字符串DoStuff(字符串x);
}
}

您应该创建一个表示
Mock.Setup
方法的表达式参数的
表达式

这意味着应该只有一个参数表达式

另外,在构建所需的表达式时,
It.IsAny()
是对静态类
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);
    }
}
[TestClass]
公共类MoqExpressionTests{
[测试方法]
public void应该构建Moq表达式(){
//安排
//我想做类似的事情:
//m、 Setup(a=>a.DoStuff(It.IsAny()).Returns(“mocked!”);
var doStuff=typeof(IBlah).GetMethod(“doStuff”,新类型[]{typeof(string)});
var isAnyOfString=typeof(It).GetMethod(“IsAny”).MakeGenericMethod(typeof(string));
//伊布拉x=>
ParameterExpression参数=表达式参数(typeof(IBlah),“x”);
//It.IsAny()
var arg=Expression.Call(isAnyOfString);
//IBlah x=>x.DoStuff(It.IsAny())
MethodCallExpression body=Expression.Call(参数,doStuff,new[]{arg});
//Func=IBlah x=>x.DoStuff(It.IsAny())
表达式=
表达式.Lambda(主体,参数);
var expected=“mocked!”;
Mock m=新的Mock(MockBehavior.Strict);
m、 设置(表达式)。返回(预期);
var subject=m.Object;
//表演
var-actual=subject.DoStuff(string.Empty);
//断言
断言.AreEqual(预期、实际);
}
公共接口IBlah{
字符串DoStuff(字符串x);
}
}
  • 您不能对其使用字符串参数。如果需要,请使用MethodCallExpression
  • 对于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));
        }
    }
    
    公共类程序
    {
    静态void Main(字符串[]参数)
    {
    Mock m=新的Mock(MockBehavior.Strict);
    //我想做类似的事情:
    //m、 Setup(a=>a.DoStuff(It.IsAny()).Returns(“mocked!”);
    var method=typeof(IBlah).GetMethod(“DoStuff”,新类型[]{typeof(string)});
    MethodInfo泛型anyMethodInfo=
    typeof(It).GetMethods().Single(e=>e.Name==“IsAny”).MakeGenericMethod(typeof(string));
    MethodCallExpre