我在尝试模拟一些在我的项目中接收复杂lambda表达式的对象时遇到了这个问题。主要是使用接收此类委托的代理对象:
Func<Tobj, Fun<TParam1, TParam2, TResult>>
我曾尝试使用Moq和RhinoMocks来模拟这些类型的对象,但两者都失败了。
这是我尝试做的简化示例:首先,我有一个计算器对象进行计算:
public class Calculator
{
public int Add(int x, int y)
{
var result = x + y;
return result;
}
public int Substract(int x, int y)
{
var result = x - y;
return result;
}
}
接下来,我需要验证Calculator类中每个方法的参数,因此为了遵守Single Responsibility原则,我创建了一个验证器类。我使用Proxy类连接所有内容,以防止重复代码:
public class CalculatorProxy : CalculatorExample.ICalculatorProxy
{
private ILimitsValidator _validator;
public CalculatorProxy(Calculator _calc, ILimitsValidator _validator)
{
this.Calculator = _calc;
this._validator = _validator;
}
public int Operation(Func<Calculator, Func<int, int, int>> operation,
int x,
int y)
{
_validator.ValidateArgs(x, y);
var calcMethod = operation(this.Calculator);
var result = calcMethod(x, y);
_validator.ValidateResult(result);
return result;
}
public Calculator Calculator { get; private set; }
}
最后,我正在测试一个使用CalculatorProxy的组件,所以我想模仿它,例如使用Rhino Mocks:
[TestMethod]
public void ParserWorksWithCalcultaroProxy()
{
var calculatorProxyMock = MockRepository.GenerateMock<ICalculatorProxy>();
calculatorProxyMock.Expect(x => x.Calculator).Return(_calculator);
calculatorProxyMock.Expect(x => x.Operation(c => c.Add, 2, 2)).Return(4);
var mathParser = new MathParser(calculatorProxyMock);
mathParser.ProcessExpression("2 + 2");
calculatorProxyMock.VerifyAllExpectations();
}
然而我无法让它发挥作用! Moq因NotSupportedException而失败,而且在RhinoMocks中它简直无法满足期望。
答案 0 :(得分:1)
我已经找到了解决方法,使用Moq:
[TestMethod]
public void ParserWorksWithCalcultaroProxy()
{
var calculatorProxyMock = new Mock<ICalculatorProxy>();
Func<Calculator, Func<int, int, int>> addMock = c => c.Add;
calculatorProxyMock.Setup(x => x.BinaryOperation(It.Is<Func<Calculator, Func<int, int, int>>>(m => m(_calculator) == addMock(_calculator)), 2, 2))
.Returns(4).Verifiable();
var mathParser = new MathParser(calculatorProxyMock.Object);
mathParser.ProcessExpression("2 + 2");
calculatorProxyMock.Verify();
}
这样我可以测试通过计算器对象上的计算器代理调用的方法,验证MathParser是否解析了表达式。
我想我可以把它转化为我的真实项目。
另外,我发现在Moq中,Lambda Expression参数支持是一个未解决的问题,针对最终的4.0版本:Moq Open Issues
修复了使用lambda表达式参数进行模拟但是它只适用于简单的lambda表达式。你可以得到它here
答案 1 :(得分:0)
最后我改变了主意。回归本源。
我需要知道的是,是否使用正确的参数调用Calculator.Add方法。所以考虑到单元测试覆盖了代理,我认为我应该模拟Calculator对象,并使用真正的代理。在不改变测试意义的情况下,它比我之前的解决方案更清晰。
使用Moq看起来像这样:
[TestMethod]
public void ParserWorksWithCalcultaroProxy()
{
var calculatorMock = new Mock<CalculatorExample.ICalculator>();
calculatorMock.Setup(x => x.Add(2, 2)).Returns(4).Verifiable();
var validatorMock = new Mock<ILimitsValidator>();
var calculatorProxy = new CalculatorProxy(calculatorMock.Object, validatorMock.Object);
var mathParser = new MathParser(calculatorProxy, new MathLexer(new MathValidator()));
mathParser.ProcessExpression("2 + 2");
calculatorMock.Verify();
}
我也开始喜欢Moq语法而不是Rhino.Mocks。