Unit testing an application that talks to microsof

2019-04-02 05:53发布

问题:

I am modifying an application that does a lot of 'talking' to Microsoft Word. Right now, COM interop is used but I need to change it to Open XML. I would like to introduce unit tests for this but I am not sure how to do this.

This is one of the operations for example: A template word document contains some bookmarks. The application fills up the bookmarks with some dynamic data. Can I check if this executes correctly?

回答1:

In order to unit test things like this, you need to design seams at the boundaries between your application and external code (Word, in this case).

For example, consider the following code:

var bookmarks = document.MainDocumentPart.Document.Body.Descendants<BookmarkStart>();
DoStuffWithBookmarks(bookmarks); // Imagine we want to unit test this method

Any code that invokes external code like this cannot be unit tested, as it is tightly coupled to the external code. That is, your tests would be testing your code and the external code, which introduces a lot of moving parts and a lot of opportunities for your test to break.

To deal with this, you introduce a layer of abstraction between your code and the external code. This lets you unit test your code by replacing the external code with test doubles.

Working with the example above:

var bookmarks = bookmarkProvider.GetBookmarks();
DoStuffWithBookmarks(bookmarks);

In your unit test, you would replace bookmarkProvider with a test double, giving you complete control over the conditions you're interested in testing.

Your production version of bookmarkProvider basically forwards its invocation to the external code:

IEnumerable<Bookmark> GetBookmarks()
{
    var wordBookmarks = m_document.MainDocumentPart.Document.Body.Descendants<BookmarkStart>();

    return ConvertToOurBookmarks(wordBookmarks); // wordBookmarks is external code!
}

Note: in this example the method does not return the Word objects directly - doing so would result in your code remaining tightly coupled to the external code. (So, not only is the process of retrieving bookmarks abstracted away, the bookmarks themselves are as well.)

This may seem like a lot of unnecessary work at first, but having the ability to test your code in complete isolation will pay dividends.