如何模拟扩展IEnumerable的接口



我使用Moq,我有以下接口:

public interface IGameBoard : IEnumerable<PieceType>
{
    ...  
}
public class GameBoardNodeFactory
{
    public virtual GameBoardNode Create (int row, int column, IGameBoard gameBoard)
    {
        ...
    }
}

然后我有一个这样的测试:

var clonedGameBoardMock = new Mock<IGameBoard> (MockBehavior.Loose);
var gameBoardNodeFactoryMock = new Mock<GameBoardNodeFactory> ();
gameBoardNodeFactoryMock.Setup (x =>
    x.Create (
        position.Row,
        position.Column,
        clonedGameBoardMock.Object)).Returns (new GameBoardNode { Row = position.Row, Column = position.Column });

但是然后gameBoardNodeFactoryMock.Object.Create (position。行,位置。Column, clonedGameBoardMock.Object)抛出NullReferenceException。我试图为IGameBoard创建一个模拟,这样它就不会扩展IEnumerable接口,然后工作

如果调用GetEnumerator(),则需要为其创建安装程序。比如:

var mockPieces = new List<PieceType>;
clonedGameBoardMock.Setup(g => g.GetEnumerator()).Returns(mockPieces.GetEnumerator());

如果这是本例中的问题,请务必注意,但如果您需要模拟IEnumerable<T>,则值得注意。

@DanBryant的答案也是我们解决方案的关键。但是,在这种情况下,枚举数可能会被意外地重用。我建议使用:

clonedGameBoardMock.Setup(g => g.GetEnumerator()).Returns(() => mockPieces.GetEnumerator());

这是一个完整的repro(使用NUnit 2.6.4和Moq 4.2的新类库):

public interface IMyThing<T> : IEnumerable<T>
{
    string Name { get; set; }
    IMyThing<T> GetSub<U>(U key);
}
public interface IGenericThing
{
    string Value { get; set; }
}
public class Pet
{
    public string AnimalName { get; set; }
}
public class Unit
{
    public IEnumerable<Pet> ConvertInput(IMyThing<IGenericThing> input)
    {
        return input.GetSub("api-key-123").Select(x => new Pet { AnimalName = x.Value });
    }
}
[TestFixture]
public class Class1
{
    [Test]
    public void Test1()
    {
        var unit = new Unit();
        Mock<IMyThing<IGenericThing>> mock = new Mock<IMyThing<IGenericThing>>();
        Mock<IMyThing<IGenericThing>> submock = new Mock<IMyThing<IGenericThing>>();
        var things = new List<IGenericThing>(new[] { new Mock<IGenericThing>().Object });
        submock.Setup(g => g.GetEnumerator()).Returns(() => things.GetEnumerator());
        mock.Setup(x => x.GetSub(It.IsAny<string>())).Returns(submock.Object);
        var result = unit.ConvertInput(mock.Object);
        Assert.That(result, Is.Not.Null.And.Not.Empty);
        Assert.That(result, Is.Not.Null.And.Not.Empty); // This would crash if the enumerator wasn't returned through a Func<>...
    }
}

为了它的价值/让这个问题弹出一个孤独的谷歌人与我有同样的问题:上面是一个抽象版本的Couchbase . net客户端的IView<T>接口,它也实现了IEnumerable<T>

在这种情况下,null引用通常意味着从未满足您的设置。这意味着它从来没有使用您设置的确切值调用。为了调试这一点,我将使用It.IsAny()等来减少匹配的约束,以确保测试将匹配对模拟函数的任何调用。在大多数情况下,这就足够了。你为什么要匹配特定的值?

如果有人感兴趣,我将Moq更新到第4版,现在一切都如预期的那样工作。

最新更新