我正在使用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.Row,position.Column,clonedGameBoardMock.Object)抛出NullReferenceException。我试图为IGameBoard创建一个模拟,这样它就不会扩展IEnumerable&lt; PieceType&gt;接口,然后它工作。
感谢任何帮助。
答案 0 :(得分:12)
如果要调用GetEnumerator(),则需要为其创建一个Setup。类似的东西:
var mockPieces = new List<PieceType>;
clonedGameBoardMock.Setup(g => g.GetEnumerator()).Returns(mockPieces.GetEnumerator());
请注意在这种情况下是否存在问题,但值得注意的是,您是否需要模拟IEnumerable<T>
。
答案 1 :(得分:4)
The answer by @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<>...
}
}
为了这个问题/使这个问题突然出现在一个单独的Google员工身上,我遇到了同样的问题:上面是Couchbase .NET客户端的IView<T>
接口的抽象版本,它也实现了{{ 1}}。
答案 2 :(得分:0)
在这种情况下,空引用通常意味着您的设置从未得到满足。这意味着它从未使用您设置的确切值调用。为了调试这个,我会通过使用It.IsAny()等来减少约束,以确保测试在对mocked函数的任何调用时都匹配。在大多数情况下,这已经足够了。您尝试匹配特定值的任何原因?
答案 3 :(得分:0)
好的,如果有人有兴趣,我将Moq更新到版本4,现在一切都按预期工作。