我正在尝试使用Moq 4.0.10827(在NuGet上)测试应用程序服务,并且需要查询存储库:
public class MyService
{
Repository<MyObject> _Repo;
public MyObject Get (string SomeConstraint)
{
return _Repo
.GetTheFirstOneOrReturnNull (M => M.Constraint.Equals (
SomeContraint, StringComparison.InvariantCultureIgnoreCase
)); // GetTheFirstOneOrReturnNull takes a Func<MyObject, bool>
}
}
如何使用Moq复制lambda表达式?我一直得到“不支持的表达式”异常。
这是我已经在做什么的想法:
[TestMethod]
public void GetByMyConstraintShouldReturnWithMyObject ()
{
// Arrange
const string MyConstraint = "Constraint";
MyObject Expected = new MyObject { Constraint = MyConstraint };
Mock<Repository<MyObject>> MockRepo = new Mock<Repository<MyObject>> ();
MockRepo.Setup (x => x.GetTheFirstOneOrReturnNull (M => M.Constraint.Equals (MyConstraint, StringComparison.InvariantCultureIgnoreCase)))
.Returns (Expected).Verifable ();
MyService Service = new MyService (MockRepo.Object);
// Act
MyObject Result = Service.Get (MyConstraint);
// Assert
Assert.AreSame (Expected, Result);
MockRepo.Verify ();
}
我已经环顾了一些其他的答案,但我无法弄清楚我做错了什么(当然是Moq的“noob”)。我得出结论,这将是一个痛苦,但我有很多这样的测试即将到来,并希望现在变得坚实,而不是以后溺水。
是将lambda表达式封装在对象内部并传入存储库并让它执行查询的唯一选项吗?我不想仅仅为了我的测试环境而改变我的代码,但我也不想浪费时间试图将这个东西弯曲到我的意愿。
这不需要太多测试。一个正确的测试将显示委托给FirstOrDefault
的代码正在工作,然后所有后续测试都在测试Func
约束中的逻辑是否正确,这可以在不将其传递到Repository
的情况下完成。
看起来你正在尝试模拟扩展方法。您不能以这种方式模拟扩展方法,因为它们实际上并未在您正在模拟的类型上声明。
在这种情况下,由于您的存储库似乎代表了一组事物,您应该替换一个简单的硬编码集合。由于您没有提供IRepository
的源代码,因此尚不清楚您可能会如何处理它。
我要说你最好的选择是更新你的Repository
有类似FindByConstraint
方法的东西,你传入的所有内容都是Constraint
,Repo本身就是FirstOrDefault()
。我认为这样做有合理的设计理由,而且只是为了让它更容易测试 - 搜索正在以不区分大小写的方式执行,并且很乐意返回null,您可以将其视为Repo应该制作的决策而不是其客户端。
我个人很难测试一个对象意味着我的设计存在缺陷,我认为对象很容易测试是值得努力的。