0

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...
Peter Dongan
  • 111
  • 3
  • 2
    I think your question isn't really different from other "unit test vs integration test" questions asked on this site in the past. Though they were not specifically for Word Addins, but the arguments are always the same .... – Doc Brown Feb 07 '23 at 16:23
  • 1
    For example: [Do I need unit test if I already have integration test?](https://softwareengineering.stackexchange.com/questions/204786/do-i-need-unit-test-if-i-already-have-integration-test)( – Doc Brown Feb 07 '23 at 16:23
  • 1
    or [Should Integration test offer more value than unit tests?](https://softwareengineering.stackexchange.com/questions/358570/should-integration-test-offer-more-value-than-unit-tests) – Doc Brown Feb 07 '23 at 16:25
  • 1
    or [Automated unit testing, integration testing or acceptance testing](https://softwareengineering.stackexchange.com/questions/39368/automated-unit-testing-integration-testing-or-acceptance-testing) – Doc Brown Feb 07 '23 at 16:26
  • @DocBrown I'm not asking about comparing unit tests and integration tests. I'm asking about comparing initializing objects for a test from a document as an embedded resource versus using wrappers and interfaces to abstract them so you can use mock/test objects instead. – Peter Dongan Feb 07 '23 at 17:38
  • 2
    Unit testing often means to isolate a "subject under test" from it's environment, and wrappers and mocks are standard techniques for this. If you think this does not match what you describe, you may give a more detailed example (by editing the question, not here in a comment, where the space would probably be too small). – Doc Brown Feb 07 '23 at 21:12
  • "I think that the tests are more readable when the state of the objects is set explicitly in the code" - I agree, and this is kind of important, especially if you are trying to test the behavior/contract (the rules, or relationships). But a lot of people don't really know how to formulate these sorts of tests, so they write tests that are more of a catch-all safety net, and that check for the exact data, rather than the rule (and so are brittle). For these sorts of tests, they likely find it easier to embed a document (or a JSON file, or use a local DB, etc.). – Filip Milovanović Feb 08 '23 at 01:04
  • What's up, Peter, I saw your edit, but still miss the example or clarification I asked for. – Doc Brown Feb 08 '23 at 04:57
  • @DocBrown Yes, I shouldn't have even been correcting the typo at the time as it was about 1.00 a.m. here - but please find the examples above now. – Peter Dongan Feb 08 '23 at 10:28
  • @Peter: do your tests with wrappers/mocks still require an MS Word process to start? I guess loading from a resource does. – Doc Brown Feb 08 '23 at 12:17
  • @DocBrown - No, there's no dependency on Word or the interop or anything else apart from the testing packages, the interfaces and the project being tested. The wrappers aren't used in the tests. Separate classes that implement the same interfaces are used instead. There's no logic in the wrappers, they just access properties of the wrapped COM object or call methods in them. The equivalent test classes have equivalent methods for things like adding comments or replies, and let you set the properties directly. – Peter Dongan Feb 08 '23 at 13:35
  • And loading from a resource requires to start an MS Word process? Then this is clearly an integration test (your addin + MS Word), whilst using wrappers counts as a unit test (testing the addin alone). For me, this looks very much as if you are asking of unit tests vs integration tests. Where do you see a difference? – Doc Brown Feb 08 '23 at 14:55

0 Answers0