模拟从IEnumerable <t>继承的抽象类

时间:2018-01-25 16:15:08

标签: c# moq

我正在尝试从我正在使用的库中模拟一个抽象类。我无权访问源代码,只能访问反编译版本:

public abstract class Event : IEnumerable<Message>, IEnumerable
{
    protected Event();
    public abstract bool IsValid { get; }
    public IEnumerator<Message> GetEnumerator();
    public IEnumerable<Message> GetMessages();        
}

这个反编译的代码让我感到困惑。首先,冗余继承,也没有非抽象方法的实现,例如GetEnumeratorIEnumerable.GetEnumerator()。但它已编译,并且它可以工作,所以我认为它只是反编译的假象(如果这甚至是一件事?)

我尝试了以下模拟,它可以编译并运行而不会抛出异常。

public static Event GetMockedEvent()
{
    var mock = new Mock<Event>();
    mock.Setup(e => e.IsValid).Returns(true);
    mock.As<IEnumerable>().Setup(e => e.GetEnumerator()).Returns(MessageList());

    return mock.Object;
}

private static IEnumerator<Message> MessageList()
{
    yield return GetMockedMessage();
    yield return GetMockedMessage();
}

private static Message GetMockedMessage()
{
    var mock = new Mock<Message>();
    // Unimportant setups...        
    return mock.Object;
}

但是我没有在我用以下方式测试的模拟对象中获得任何元素

var ev = GetMockedEvent();
foreach (var msg in ev)
{
    //
}

但枚举是空的,我无法弄清楚原因。我已经对这个问题感到头疼了整整一天,所以我非常感谢你的帮助。

亲切的问候

3 个答案:

答案 0 :(得分:3)

当您foreach超过一个序列时,IIRC编译器会将其视为对GetEnumerator的通用版本的调用,因此这是您必须模拟的那个。

这样的事情可能会起作用,虽然我没有尝试过:

public static Event GetMockedEvent()
{
    var mock = new Mock<Event>();
    mock.Setup(e => e.IsValid).Returns(true);
    mock.As<IEnumerable<Message>>()
        .Setup(e => e.GetEnumerator())
        .Returns(() => MessageList());

    return mock.Object;
}

答案 1 :(得分:2)

Event有三个公共成员(以及一个明确实现的接口方法)。你已经嘲笑了其中两个,然后编写了使用第三个的测试代码。如果你希望它在你的测试代码中返回一些东西,你需要实际模拟GetEnumerator实现(当然你也应该模拟非泛型版本,以防其他一些测试代码试图使用它)。

答案 2 :(得分:2)

前言 您粘贴的Event类的代码只是元数据表示形式。如果您真的想查看其源代码,请使用完整的反编译器,例如ILSpyVS extension)。 结束前言

Event类不能完全嘲笑,因为GetEnumerator不是虚拟的(至少就你的代码片段而言),所以

  • 你必须按原样使用它的身体;和
  • 即使是模拟库也无法取代它。

由于类隐式实现IEnumerable<Message>foreach循环直接调用声明的方法,而不是&#34;显式实现&#34;您使用GetMockedEvent方法进行设置。

要清楚,下面是我试图运行的完整代码段。我决定抛出NotImplementedException作为&#34;中立&#34;替换未知的方法体。

void Main()
{
    var ev = GetMockedEvent();
    foreach (var msg in ev)
    {
        Console.WriteLine(msg);
    }
}

public abstract class Event : IEnumerable<Message>, IEnumerable
{
    protected Event() { }
    public abstract bool IsValid { get; }
    public IEnumerator<Message> GetEnumerator() { throw new NotImplementedException(); }
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public IEnumerable<Message> GetMessages() { throw new NotImplementedException(); }     
}

public class Message { }

public static Event GetMockedEvent()
{
    var mock = new Mock<Event>();
    mock.Setup(e => e.IsValid).Returns(true);
    mock.As<IEnumerable<Message>>().Setup(e => e.GetEnumerator()).Returns(MessageList());
    // The next line doesn't work either because the method is not virtual
    //mock.Setup(e => e.GetEnumerator()).Returns(MessageList());

    return mock.Object;
}

private static IEnumerator<Message> MessageList()
{
    yield return GetMockedMessage();
    yield return GetMockedMessage();
}

private static Message GetMockedMessage()
{
    var mock = new Mock<Message>();
    // Unimportant setups...
    return mock.Object;
}