【问题标题】:How to mock System.Xml.XmlWriter.WriteAttributeString() with moq?如何用 moq 模拟 System.Xml.XmlWriter.WriteAttributeString()?
【发布时间】:2012-12-13 18:23:49
【问题描述】:

当我在测试中运行以下代码时,

Mock<XmlWriter> mockXmlWriter = new Mock<System.Xml.XmlWriter>();
Language language = Language.GetLangauge(langId);
language.WriteXml(mockXmlWriter.Object);
mockXmlWriter.Verify(writer => writer.WriteAttributeString("ID", language.LanguageID.ToString()));

Moq 抛出以下异常是可以理解的:System.NotSupportedException : Invalid verify on a non-virtual (overridable in VB) member: writer =&gt; writer.WriteAttributeString("ID", .language.LanguageID.ToString())。

愚蠢的抽象XmlWriter 仍然有一些非抽象、非虚拟的方法,比如WriteAttributeString() :(

我寻找XmlWriterBase 或System.Xml.Abstractions,就像我寻找HttpContext 和公司一样,但一无所获:(

我将如何克服这个问题,以便我可以测试我的 WriteXml 方法是否正在做它应该做的事情?

【问题讨论】:

  • 您是否尝试过创建子类、覆盖方法并将其标记为虚拟>
  • 我这样做了,现在Verify() 抱怨WriteAttributeString() 永远不会被调用。当我单步执行代码时,显然是:(

标签: c# mocking nunit moq xmlwriter


【解决方案1】:

根据经验,模拟你不拥有的类是一个坏主意,因为你无法完全控制它们,这可能会导致问题(比如你的)。

我认为您可以在这里安全地使用真正的XmlWriter,它将其输出写入MemoryStream,并简单地断言流包含预期的XML:

// arrange
MemoryStream underlyingStream = new MemoryStream();
XmlWriter xmlWriter = XmlWriter.Create(underlyingStream);
Language language = Language.GetLangauge(langId);

// act
language.WriteXml(xmlWriter);

// assert
underlyingStream.Position = 0;
using (StreamReader streamReader = new StreamReader(underlyingStream)
{
    string createdXml = streamReader.ReadToEnd();
    Assert.That(createdXml, Is.EqualTo("expectedXml"));
}

断言部分可以很好地重构为辅助方法。最近写了一个处理 XML 创建的代码,我对它很感兴趣 - 起初,我的测试是基于模拟的,而且本质上,它们是生产代码的精确副本。幸运的是,在进行到一半时,我决定将整个东西重构为类似于我示例中的样式,这确实很有帮助 - 测试现在变得不那么脆弱,一切都变得更简单了。

【讨论】:

  • 我认为模拟的主要用途之一是模拟你不拥有的类。
  • @mo。在嘲笑 3rd 方课程时,我被烧了很多次,现在我在做之前真的很努力。 This article 很好地组合在一起。另外,如果你能接触到this wonderful book,它有一整章专门讨论这个问题。
  • @mo。模拟用于替换具有副作用的依赖项:文件 I/O、网络流量、数据库写入等。然而,限制是您不能模拟静态成员 (DateTime.Now)、密封类 (System.String) 或非虚拟成员,正如您现在所击中的那样。我建议不要嘲笑第 3 方课程。如果您对具有副作用的 3rd 方对象有依赖关系,则将该依赖关系替换为接口,并模拟它。
  • @更多。 "How do you replace a 3rd party implementation with an interface?" 如果您需要模拟依赖项的行为,那么您在问题中所说的话听起来不错。 IE。制作接口,模拟接口;然后实现接口,它只是一个非常薄的包装器。这不必增加风险,因为您已经有调用 XmlWriter 的代码,只是之前它不在单独的类中。如果您还想测试包装器代码,那么包装器类可能是一些调用真正 XmlWriter 的测试的理想选择。
  • @mo。是的,您确实可以说XmlWriter 和您的Language 类都通过一个测试进行了测试。虽然我确信这会受到许多 TDD 纯粹主义者的反对,但我认为这是一件务实的事情。现实地说 - XmlWriter 是否有可能包含会以意想不到的方式影响您的测试的错误?我不这么认为。另一方面,如果您确实使用它,我相信您的测试将更容易理解和维护。不过,最后,做你感觉最好的事情;你也可以考虑@Daryn 的方法。
猜你喜欢
  • 2016-08-06
  • 2012-03-18
  • 2010-10-19
  • 2016-09-30
  • 2019-10-06
  • 1970-01-01
  • 2020-10-27
  • 2012-06-01
  • 2018-12-27
相关资源
最近更新 更多