We are developing Word Addins that interact with elements in Word documents.
To make it testable, my approach has been to use interfaces and wrappers for UI elements, and then provide mock alternative implementations to the wrappers. For example, IDocument wraps a COM Document object and provides accessors to the relevant members. For testing, I can use a MockDocument that also implements the interface, and I can just set the properties manually for testing.
I see that in other projects the approach is to use a test Word document as an embedded resource, and to initialize the COM controls from that for the tests.
I'm happy that the interface/wrapper approach is a better fit for my project because I need to the code to recognize changes to the document at different points in time. This is certainly easier to represent by changing properties directly in a custom mock object than using multiple documents as embedded resources.
However, I'm trying to form a more complete picture of how these approaches compare in a more general sense. Here are my thoughts so far...
If you use an embedded resource, then there is a dependency on that, so is this strictly a unit test? If not, is there clear value in using a true unit test that this approach doesn't offer, or is the difference only academic?
I think that the tests are more readable when the state of the objects is set explicitly in the code, and not when it is initialized from a document that is an embedded resource. Therefore it is more useful as a source of documentation. I wonder if this view could be considered subjective though?
The interface/wrapper approach has a stronger influence on encouraging well-structured code, as you can pass in the specific elements you are using in your tests, and not need to initialize things from whole documents.
The interface/wrapper only needs to expose the members of the wrapped COM objects that are used by the software. This improves code readability as it hides a lot of stuff that we don't need to know about when we are using the COM objects.
There is some additional work involved in setting up the interfaces and wrappers compared to using the COM objects directly, but I think it is justified by the value it offers.
Edit: Examples of approaches:
Interfaces/wrappers example
[Test]
public void TestTextChanged()
{
var mockWordComment = new MockWordComment("Original text", "John Smith");
var commentUnderTest = new CommentViewModel(mockWordComment, _logger); // CommentViewModel takes IWordComment as an argument, which can be a wrapper for an actual word comment, or a test object like what is used here.
mockWordComment.Text = "Changed text";
commentUnderTest.UpdateFromWordComment();
Assert.IsTrue(commentUnderTest.IsNew == false);
Assert.IsTrue(commentUnderTest.IsTextChanged);
//...other assert statements...
Initializing test data from file example:
[TestMethod]
public void TableTest1()
var wpdocument = InitializeFromFile("path/to/file");
Table table = wpdocument.MainDocumentPart.Document.Body.Elements<Table>().First();
Assert.IsNotNull(table);
// ...other assert statements...