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

Building an IDE, block by -- er, mock by mock

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

Problem

The opening sentence of an answer I received in my previous post snowballed, and led to completely ditching the previous approach. Mocking my IDE with a MockFactory worked ok, ...for some values of "ok" - the more components needed to be involved, the messier the setup code was getting.

So instead of manufacturing mocks, I thought I'd build them. Enter the MockVbeBuilder API:

Mock mock = new MockVbeBuilder()
    .ProjectBuilder("TestProject1", vbext_ProjectProtection.vbext_pp_none)
    .AddComponent("TestModule1", vbext_ComponentType.vbext_ct_StdModule, contentForProject1Module1)
    .AddComponent("TestModule2", vbext_ComponentType.vbext_ct_StdModule, contentForProject1Module2)
    .UserFormBuilder("UserForm1", codeBehindForProject1UserForm1)
    .AddControl("Button1")
    .AddControl("Button2")
    .MockProjectBuilder()
    .AddComponent("TestClass1", vbext_ComponentType.vbext_ct_ClassModule, contentForProject1Class1)
    .AddComponent("ThisWorkbook", vbext_ComponentType.vbext_ct_Document, contentForProject1ThisWorkbook)
    .MockVbeBuilder()
    .ProjectBuilder("TestProject2", vbext_ProjectProtection.vbext_pp_locked)
    .AddComponent("TestClass1", vbext_ComponentType.vbext_ct_ClassModule, contentForProject2Class1)
    .AddReference("TestProject1", "PathToProject1")
    .MockVbeBuilder()
    .Build();


I also exposed a "shortcut" builder, to mock the entire IDE out of just a single standard module:

VBComponent component;
Mock mock = new MockVbeBuilder().BuildFromSingleStandardModule(content, out component);


This simplifies usage for the simpler tests that really only need a single code module with some test content.

Here's the MockVbeBuilder class:

```
namespace RubberduckTests.Mocks
{
///
/// Builds a mock .
///
public class MockVbeBuilder
{
private readonly Mock _vbe;

private Mock _vbProjects;
private readonly ICollection _projects = new List();

private Mock _vbCodePanes;

Solution

It's very hard to follow the builder when it's jumping around like it is... I wonder whether you could achieve something like:

var Mock mock = new MockVbeBuilder()
        .AddProject(settings => 
        {
            settings.Name = "";
            settings.Protection = /* something... */;
            settings.ComponentBuilder
                    .AddComponent("TestModule1",
                            vbext_ComponentType.vbext_ct_StdModule, 
                            contentForProject1Module1)
                    .AddComponent("TestModule2", 
                            vbext_ComponentType.vbext_ct_StdModule,
                            contentForProject1Module2);
        })
        .Build();


It's probably going to complicate the design a bit but I think the addition of some Settings type objects may help you in the long run.

I realise that the above isn't really a review of your code... I can whine about some of your naming if you'd like ;)

Naming

You're inconsistent with capitalisation on Vbe/VBE the class is VBE but you CreateVbeMock. I'm guessing that's because VBE is a generated class?

The documentation for MockProjectBuilder (and what it does) is a lot more than just navigating to the project builder.

UserFormBuilder method doesn't quite follow the pattern elsewhere - should be MockUserFormBuilder.

Those are the only ones that I can see... Your code is getting too consistently good to pick out many things!

I wonder whether calling your methods that navigate to a parent builder ToXyzBuilder would make the code read a bit better?

Code Snippets

var Mock<VBE> mock = new MockVbeBuilder()
        .AddProject(settings => 
        {
            settings.Name = "";
            settings.Protection = /* something... */;
            settings.ComponentBuilder
                    .AddComponent("TestModule1",
                            vbext_ComponentType.vbext_ct_StdModule, 
                            contentForProject1Module1)
                    .AddComponent("TestModule2", 
                            vbext_ComponentType.vbext_ct_StdModule,
                            contentForProject1Module2);
        })
        .Build();

Context

StackExchange Code Review Q#96859, answer score: 6

Revisions (0)

No revisions yet.