如何模拟扩展 IEnumerable 的接口

发布于 2024-10-30 08:17:52 字数 912 浏览 1 评论 0原文

我正在使用 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界面然后就可以工作了。

任何帮助表示赞赏。

I'm using Moq and I have the following interface:

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

Then I have a test like this:

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

But then gameBoardNodeFactoryMock.Object.Create (position.Row, position.Column, clonedGameBoardMock.Object) throws a NullReferenceException. I tried to create a mock for the IGameBoard such that it doesn't extend IEnumerable<PieceType> interface and then it works.

Any help is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

打小就很酷 2024-11-06 08:17:52

如果调用 GetEnumerator(),则需要为它创建一个安装程序。类似于:

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

请注意确定这是否是本例中的问题,但如果您需要模拟 IEnumerable,则值得注意。

You would need to create a Setup for GetEnumerator() if it's being called. Something like:

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

Note sure if that's the issue in this case, but worth noting if you ever need to mock IEnumerable<T>.

抱猫软卧 2024-11-06 08:17:52

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

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

这是一个完整的重现(使用 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 接口的抽象版本,它还实现 IEnumerable

The answer by @DanBryant was also the key to our solution. However, the enumerator in that case might be accidentally reused. Instead, I suggest using:

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

Here's a full repro (new class library using NUnit 2.6.4 and 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<>...
    }
}

For what it's worth / to make this question pop up to that one lone Googler with the same problem I had: the above is an abstracted version of the Couchbase .NET client's IView<T> interface, which also implements IEnumerable<T>.

笑着哭最痛 2024-11-06 08:17:52

在这种情况下,空引用通常意味着您的设置从未得到满足。这意味着它永远不会以您设置的确切值来调用。为了调试这个,我将通过使用 It.IsAny() 等来减少匹配的限制,以确保测试将匹配对模拟函数的任何调用。在大多数情况下,这已经足够了。您尝试匹配特定值的原因是什么?

A null reference in this situation usually means your setup was never met. Meaning it was never called with the exact values you set it up for. To debug this I would make your match less constraining by using It.IsAny() and so on to make sure the test will match on any call to the mocked function. In most cases this is good enough. Any reason why your are trying to match on specific values?

眼波传意 2024-11-06 08:17:52

好吧,如果有人感兴趣,我将 Moq 更新到版本 4,现在一切都按预期进行。

Okay if anyone is interested, I updated Moq to version 4 and now everything works as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文