我想要moq一个具有索引的属性,并且我希望能够在回调中使用索引值,就像在moq方法的回调中使用方法参数一样。可能最容易用一个例子来证明:
public interface IToMoq
{
int Add(int x, int y);
int this[int x] { get; set; }
}
Action<int, int> DoSet = (int x, int y) =>
{
Console.WriteLine("setting this[{0}] = {1}", x, y);
throw new Exception("Do I ever get called?");
};
var mock = new Mock<IToMoq>(MockBehavior.Strict);
//This works perfectly
mock.Setup(m => m.Add(It.IsAny<int>(), It.IsAny<int>()))
.Returns<int, int>((a, b) => a + b);
//This compiles, but my callback never seems to be called
mock.SetupSet(m => m[It.IsAny<int>()] = It.IsAny<int>())
.Callback(DoSet);
var obj = mock.Object;
Console.WriteLine("Add(3,4) => {0}", obj.Add(3, 4)); //Works perfectly
obj[1] = 2; //Does not throw, why?
编辑:为了澄清,我希望get
的回调/返回方法为Func<int,int>
,并且set
的回调/返回方法为Action<int,int>
。尝试Mike建议的内容,您可以为set
执行此操作,但有一个主要限制:
mock.SetupSet(m => m[23] = It.IsAny<int>())
.Callback(DoSet).Verifiable();
然后确实使用值DoSet
调用回调(23,<any>)
。不幸的是,使用It.IsAny<int>()
代替23
似乎表现为0
,而不是<any>
。
另外,我找不到用SetupGet
调用Returns
的方法,其中Returns
采用甚至可以编译的Func<int,int>
。
是否可以使用Moq?
动机:我只是在玩Moq,试图用它来提供一个流畅的API来执行拦截。也就是说,给定I
的接口X
和I
的实例Mock<I>
,会自动创建一个行为默认为X
的{{1}}代理。
直接使用Castle DP可能更有意义,但我喜欢Moq Expression Tree语法。
答案 0 :(得分:1)
从.NET Framework 4.5的Moq 4.2.1502.0911开始,我发现以下行为是正确的。
您遇到的问题主要是由It.IsAny<T>
电话引起的。如果使用It.IsAny<T>
,则回调不会执行:
[Test]
public void DoesNotExecuteCallback()
{
// Arrange
var mock = new Mock<IIndexable>();
var called = false;
mock.SetupSet(m => m[It.IsAny<int>()] = It.IsAny<int>()).Callback<int,int>((x, y) => called = true);
var instance = mock.Object;
// Act
instance[1] = 2;
// Arrange
Assert.That(called, Is.False);
}
但是如果你使用特定参数调用它,它会调用回调函数:
[Test]
public void DoesExecuteCallback()
{
// Arrange
var mock = new Mock<IIndexable>();
var called = false;
mock.SetupSet(m => m[1] = 2).Callback<int,int>((x, y) => called = true);
var instance = mock.Object;
// Act
instance[1] = 2;
// Arrange
Assert.That(called, Is.True);
}
总而言之,在尝试设置索引器的期望时,应避免使用It.IsAny
。一般来说,你应该避免使用它,因为可以鼓励草率的测试写作
是适用于It.IsAny
的用例,但我不知道我倾向于推荐的具体内容。
答案 1 :(得分:1)
方法SetupSet
采用普通委托,而不是类似许多其他Moq方法的Expression<...>
类型的表达式树。
出于这个原因,Moq看不到你使用了It.IsAny
。相反,It.IsAny
称为 (不是我们想要的),而Moq只看到它的返回值恰好是default(int)
或{{1 }}