简体   繁体   English

Moq是一个索引属性,并使用返回/回调中的索引值

[英]Moq an indexed property and use the index value in the return/callback

I want to moq a property that has an index, and I want to be able to use the index values in the callback, the same way you can use method arguments in the callback for moq'd methods. 我想要moq一个具有索引的属性,并且我希望能够在回调中使用索引值,就像在moq方法的回调中使用方法参数一样。 Probably easiest to demonstrate with an example: 可能最容易用一个例子演示:

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? 

Edit: To clarify, I want the callback/returns method for the get to be Func<int,int> , and the callback/returns method for the set to be Action<int,int> . 编辑:为了澄清,我希望get的回调/返回方法是Func<int,int> ,并且set的回调/返回方法是Action<int,int> Trying what Mike suggested, you can sort of do this for set , but with one major limitation: 尝试迈克建议,你可以为set做这个,但有一个主要的限制:

mock.SetupSet(m => m[23] = It.IsAny<int>())
            .Callback(DoSet).Verifiable();

The callback DoSet is indeed then called with values (23,<any>) . 然后使用值(23,<any>)调用回调DoSet Unfortunately, using It.IsAny<int>() instead of 23 seems to behave as 0 , rather than <any> . 不幸的是,使用It.IsAny<int>()而不是23似乎表现为0 ,而不是<any>

Also, I couldn't find a way of calling SetupGet with Returns where Returns takes a Func<int,int> that would even compile. 另外,我找不到使用Returns调用SetupGet的方法,其中Returns采用甚至可以编译的Func<int,int>

Is it possible to use Moq for this? 是否可以使用Moq?

Motivation: I'm just playing with Moq, attempting to use it to provide a fluent API for performing interception. 动机:我只是在玩Moq,试图用它来提供一个流畅的API来执行拦截。 That is, given an interface I and an instance X of I , automatically create a Mock<I> proxy with behaviour defaulting to X . 即,给定的接口I和实例XI ,自动创建一个Mock<I>与行为默认为代理X

Would probably make more sense to work directly with Castle DP, but I like the Moq Expression Tree syntax. 直接使用Castle DP可能更有意义,但我喜欢Moq Expression Tree语法。

As of Moq 4.2.1502.0911 for .NET Framework 4.5, I found the following behavior to be true. 从.NET Framework 4.5的Moq 4.2.1502.0911开始,我发现以下行为是正确的。

The problem you're running into is specifically due to the It.IsAny<T> call. 您遇到的问题特别是由于It.IsAny<T>调用。 If you use It.IsAny<T> , the callback does not execute: 如果使用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);
}

But if you call it using specific parameters, it calls the callback: 但是如果你使用特定参数调用它,它会调用回调:

[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);
}

To summarize, you should avoid the use of the It.IsAny when trying to setup expectations for an indexer. 总而言之,在尝试设置索引器的期望时,应避免使用It.IsAny In general, you should be avoiding the use of it because it can encourage sloppy test writing 一般来说,你应该避免使用它,因为它可以鼓励草率的测试写作

There are appropriate use cases for It.IsAny , but without knowing the specifics I tend to recommend against it. 适当的用例It.IsAny ,但不知道我倾向于建议反对的具体细节。

The method SetupSet takes a plain delegate, not an expression tree of type Expression<...> like many other Moq methods. 方法SetupSet采用普通委托,而不像许多其他Moq方法那样使用Expression<...>类型的表达式树。

For that reason Moq cannot see that you used It.IsAny . 出于这个原因,Moq看不到您使用过It.IsAny Instead, It.IsAny is called (not what we want) and Moq sees its return value only which happens to be default(int) , or 0 . 相反, It.IsAny调用 (不是我们想要的),而Moq只看到它的返回值恰好是default(int)0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM