繁体   English   中英

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

[英]Mocking an abstract class that inherits from IEnumerable<T>

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

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)
{
    //
}

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

亲切的问候

当你foreach一个序列,IIRC编译器会desugar,要到通用版的调用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;
}

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

前言您粘贴的Event类的代码只是元数据表示。 如果你真的想看到它的源代码,请使用完整的反编译器,如ILSpyVS扩展 )。 结束前言

Event类as-is无法完全模拟,因为GetEnumerator不是虚拟的(至少就你的代码片段而言),所以

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

由于该类隐式实现IEnumerable<Message> ,因此foreach循环直接调用声明的方法,而不是您在GetMockedEvent方法中设置的“显式实现”。

要清楚,下面是我试图运行的完整代码段。 我决定将NotImplementedException作为未知方法体的“中性”替换。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM