[英]Moq.Mock<T> setting up expressions into a Mock using MOQ results in mock setups not being matched
我正在尝试模拟数据服务上下文,为此,我有一个方法可以接受
当我尝试模拟此方法时,MOQ总是返回一个
模拟上的所有调用都必须具有相应的设置。 TearDown:Moq.MockException:以下设置不匹配:IContext m => m.Retrieve(It.IsAny()})
接口/实现下面的代码
public interface IContext
{
IQueryable<T> Retrieve<T>(Expression<Func<T, bool>> predicate,
string entitySetName = null,
params Expression<Func<T, object>>[] eagerProperties);
}
public class Context : IContext
{
private readonly DataServiceContext _context;
public Context(DataServiceContext context)
{
this._context = context;
}
public IQueryable<T> Retrieve<T>(Expression<Func<T, bool>> predicate,
string entitySetName = null,
params Expression<Func<T, object>>[] eagerProperties)
{
DataServiceQuery<T> query = _context.CreateQuery<T>(entitySetName ?? "Default");
return eagerProperties.Aggregate(query, (current, e) => current.Expand(e.ToString())).Where(predicate);
}
}
下面是一个调用上述上下文方法的测试类
public class Test
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
public class SomeController
{
private IContext _context = new Context(
new DataServiceContext(new Uri("http://whatever/someservice.svc/")));
public IContext ServiceContext
{
get
{
return _context ??
(_context = new Context(new DataServiceContext(new Uri("http://whatever/someservice.svc/"))));
}
set
{
_context = value;
}
}
public Test RetrieveSomeInformation()
{
IQueryable<Test> tests = _context.Retrieve<Test>
(
//Param 1
t => t.Prop1 == "test" && 1 == 1,
//Param 2
"Test",
//Param 3
t => t.Prop1,
t => t.Prop2,
t => t.Prop3
);
return tests.First();
}
}
以下是MOQ失败的实际测试,其中包含“模拟中的所有调用都必须具有相应的设置”。 看不出为什么地球上的设备无法匹配! 任何帮助,将不胜感激。
[TestFixture]
public class ControllerTests
{
public MockRepository Repository { get; set; }
protected Mock<IContext> MockContext { get; set; }
public SomeController Controller;
public List<Test> Tests;
public Test Test;
[SetUp]
public void SetUp()
{
Test = new Test { Prop1 = "1", Prop2 = "2", Prop3 = "3" };
Tests = new List<Test> { Test };
Repository = new MockRepository(MockBehavior.Strict);
MockContext = Repository.Create<IContext>();
Controller = new SomeController { ServiceContext = MockContext.Object };
}
[TearDown]
public void TearDown()
{
Repository.VerifyAll();
}
[Test]
public void DetailProgramme_Test()
{
MockContext.Setup(m => m.Retrieve<Test>
(
//Param 1
It.IsAny<Expression<Func<Test, bool>>>(),
//Param 2
It.IsAny<string>(),
//Param 3
It.IsAny<Expression<Func<Test, object>>>()
)
).Returns(Tests.AsQueryable());
Test info = Controller.RetrieveSomeInformation();
//myMock.Setup(r => r.Find(It.IsAny<Expression<Func<Person, bool>>>())).Returns(new List<Person>() { new Person() }.AsQueryable());
Assert.IsTrue(info == Test);
}
}
我相信这取决于您的设置...
//Param 3
It.IsAny<Expression<Func<Test, object>>>()
哪个与params数组不匹配。 尝试...
//Param 3
It.IsAny<Expression<Func<Test, object>>[]>()
使用不带.CallBack
Moq的It.IsAny<>
.CallBack
强制您编写测试未涵盖的代码。 相反,它完全允许任何查询/表达式通过,从单元测试的角度来看,使您的模拟基本上毫无用处。
解决方案:您要么需要使用回调来测试表达式,要么需要更好地约束模拟。 任一种方法都是麻烦且困难的。 自从我一直在练习TDD以来,我就一直在处理这个问题。 最后,我召集了一个辅助类,使它更具表现力,并且减少了混乱。 这是一个可能的最终结果:
mockPeopleRepository
.Setup(x => x.Find(ThatHas.AnExpressionFor<Person>()
.ThatMatches(correctPerson)
.And().ThatDoesNotMatch(deletedPerson)
.Build()))
.Returns(_expectedListOfPeople);
以下是讨论该博客并提供源代码的博客文章: http : //awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/
从中派生实例之后,便要设置Mock。 获得对象后,将不会受到模拟更改的影响。 例:
object instance = mock.Object; // this version wont include what you have configured in the setup
mock.Setup(...);
object instance2 = mock.Object; // get the latest version including whatever you have configured in the setup
修改代码的一种简便方法是从Setup方法中删除实例化语句,并使您的Controller变得懒惰,例如:
public SomeController Controller = new Lazy<SomeController>(() => new SomeController() { ServiceContext = MockContext.Object });
这样,只要您在设置后第一次使用控制器,就将始终使用最新版本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.