使用复杂的 Lambda 表达式作为参数来模拟对象
我在尝试模拟一些在我的项目中接收复杂 lambda 表达式的对象时遇到了这个问题。主要是使用接收此类委托的代理对象:
Func<Tobj, Fun<TParam1, TParam2, TResult>>
我尝试使用 Moq 以及 RhinoMocks 来完成对这些类型的对象的模拟,但是两者都失败了。
这是我想要做的简化示例:首先,我有一个执行计算的 Calculator 对象:
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 类中每个方法的参数,因此为了遵循单一职责原则,我创建验证器类。我使用 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 中它永远无法满足期望。
I´m encountering this problem trying to mock some objects that receive complex lambda expressions in my projects. Mostly with with proxy objects that receive this type of delegate:
Func<Tobj, Fun<TParam1, TParam2, TResult>>
I have tried to use Moq as well as RhinoMocks to acomplish mocking those types of objects, however both fail.
This is simplified example of what I´m trying to do: first, I have a Calculator object that does calculations:
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;
}
}
Next, I need to validate parameters on every method in the Calculator class, so to keep with the Single Responsibility principle, I create a validator class. I wire everything up using a Proxy class, that prevents having duplicate code:
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; }
}
Finally, I´m testing a component that does use the CalculatorProxy, so I want to mock it, for example using 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();
}
However I cannot get it to work! Moq fails with NotSupportedException, and in RhinoMocks simpy it never gets to satisfy the expectations.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我找到了一种使用 Moq 解决此问题的方法:
这样我可以测试通过计算器对象上的计算器代理调用什么方法,验证 MathParser 是否能够解析表达式。
我想我能够将其转化为我的实际项目。
另外,我发现在 Moq 中,Lambda 表达式参数支持是一个未解决的问题,针对的是最终 4.0 版本:Moq 开放问题
有一个针对使用 lambda 表达式参数进行模拟的修复,但它仅适用于简单的 lambda 表达式。您可以在此处获取它
I have found a way around this using Moq:
This way i can test what method is being called through the calculator proxy on the calculator object, verifying that the MathParser does it job parsing the expression.
I think Im going to be able to traslate this to my real projects.
Also, I found that in Moq, Lambda Expression parameter support is an open issue, that is targeted to the final 4.0 release: Moq Open Issues
There is a fix to mocking with lambda expression parameters however it does work only with simple lambda expressions. You can get it here
最后我改变了主意。回到基础。
我需要知道的是 Calculator.Add 方法是否被使用正确的参数调用。因此,鉴于它具有单元测试涵盖的代理,我认为我应该模拟计算器对象,并使用真正的代理。它比我之前的解决方案更清晰,而且没有改变测试的含义。
使用 Moq 看起来像这样:
而且我开始更喜欢 Moq 语法而不是 Rhino.Mocks。
Finally I have changed my mind. Back to basics.
What I need to know is whether the Calculator.Add method gets called with the correct arguments. So given that it have the proxy covered by unit tests, I think that I should mock the Calculator object, and use the real proxy. It's way clearer than my previous solution without changing the meaning of the test.
Using Moq looks like this:
Also I´m starting to prefer Moq syntax instead of Rhino.Mocks.