如何模拟扩展IEnumerable的接口
本文关键字:扩展 IEnumerable 接口 模拟 何模拟 | 更新日期: 2023-09-27 17:48:57
我使用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版,现在一切都如预期的那样工作。