Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock System.Xml.XmlWriter.WriteAttributeString() with moq?

When I run the following code in my test,

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 understandably throws the following exception: System.NotSupportedException : Invalid verify on a non-virtual (overridable in VB) member: writer => writer.WriteAttributeString("ID", .language.LanguageID.ToString()).

Stupid abstract XmlWriter still has some non-abstract, non-virtual methods, like WriteAttributeString() :(

I looked for an XmlWriterBase or a System.Xml.Abstractions, like I do for HttpContext and Co., but found nothing :(

How would I overcome this so I can test that my WriteXml method is doing what it's supposed to be doing?

like image 821
mo. Avatar asked Dec 13 '12 18:12

mo.


1 Answers

As a rule of thumb, it is a bad idea to mock out classes you don't own, since you do not have a full control over them and that can result in problems (such as yours).

I think you can safely use a real XmlWriter here that would write its output to a MemoryStream and that simply assert that the stream contains the expected 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"));
}

The assertion part can be nicely refactored out to a helper method. Having recently written a code dealing with XML creating, I got burned on it pretty badly - at first, my tests were mock-based and essentialy, they were an exact copies of the production code. Fortunately, halfway through I've decided to refactor the whole thing to the style similar to one in my example and it really helped - tests are now much less fragile and everything is simpler.

like image 59
Nikola Anusev Avatar answered Oct 31 '22 02:10

Nikola Anusev