HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMajor

Go on, mock my IDE

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
mockidestackoverflow

Problem

Because of the coupling with the VBIDE API (the extensibility library for the VBA IDE), unit testing the rubberduck refactorings, inspections and quick-fixes has been pretty much impossible, at least until a MockFactory was implemented, to do things like this:

internal static Mock CreateCodeModuleMock(string code)
{
    var lines = code.Split(new[] {Environment.NewLine}, StringSplitOptions.None).ToList();

    var codeModule = new Mock();
    codeModule.SetupGet(c => c.CountOfLines).Returns(lines.Count);

    codeModule.Setup(m => m.get_Lines(It.IsAny(), It.IsAny()))
        .Returns((start, count) => String.Join(Environment.NewLine, lines.Skip(start - 1).Take(count)));

    codeModule.Setup(m => m.ReplaceLine(It.IsAny(), It.IsAny()))
        .Callback((index, str) => lines[index - 1] = str);

    codeModule.Setup(m => m.DeleteLines(It.IsAny(), It.IsAny()))
        .Callback((index, count) => lines.RemoveRange(index - 1, count));

    codeModule.Setup(m => m.InsertLines(It.IsAny(), It.IsAny()))
        .Callback((index, newLine) => lines.Insert(index - 1, newLine));

    return codeModule;
}


The MockFactory is used extensively in an abstract class from which to derive all unit tests that need to work with the VBIDE API:

```
using System.Collections.Generic;
using System.Linq;
using Microsoft.Vbe.Interop;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Rubberduck.VBEditor;
using MockFactory = RubberduckTests.Mocks.MockFactory;

namespace RubberduckTests
{
public abstract class VbeTestBase
{
private Mock _ide;
private ICollection _projects;

[TestInitialize]
public void Initialize()
{
_ide = MockFactory.CreateVbeMock();
_ide.SetupProperty(m => m.ActiveCodePane);
_ide.SetupProperty(m => m.ActiveVBProject);
_ide.SetupGet(m => m.SelectedVBComponent).Returns(() => _ide.Object.ActiveCodePane.CodeModule.Parent);
_ide.SetupGet(m => m

Solution

if (moduleName == null)
{
    moduleName = componentType == vbext_ComponentType.vbext_ct_StdModule 
        ? "Module1" 
        : componentType == vbext_ComponentType.vbext_ct_ClassModule
            ? "Class1"
            : componentType == vbext_ComponentType.vbext_ct_MSForm
                ? "Form1"
                : "Document1";
}


Sorry, that I have to say this, but this is UGLY. Why don't you use a dictionary which is easily expandable if needed and would make the getting of the moduleName more shining?

If you don't want a dictionary, you really should extract it to a separate method where you simply should use a switch instead of this ugly and unreadable ternary construct.

Checking items for null by using an if statement and if it is null assign a default value, so it can be handled nicer using the null coalescing operator ??.

So for example this:

if (componentType == null)
{
    componentType = vbext_ComponentType.vbext_ct_StdModule;
}


would become this:

componentType = componentType ?? vbext_ComponentType.vbext_ct_StdModule;


After a second glance at the abstract class VbeTestBase I wonder why you decided to make this class abstract. You don't have neither abstract methods nor properties, hence there isn't any reason why this class should be abstract.

Code Snippets

if (moduleName == null)
{
    moduleName = componentType == vbext_ComponentType.vbext_ct_StdModule 
        ? "Module1" 
        : componentType == vbext_ComponentType.vbext_ct_ClassModule
            ? "Class1"
            : componentType == vbext_ComponentType.vbext_ct_MSForm
                ? "Form1"
                : "Document1";
}
if (componentType == null)
{
    componentType = vbext_ComponentType.vbext_ct_StdModule;
}
componentType = componentType ?? vbext_ComponentType.vbext_ct_StdModule;

Context

StackExchange Code Review Q#96319, answer score: 20

Revisions (0)

No revisions yet.