Search code examples
excelvbaunit-testingrubberduck

How can I deliver an Excel VBA app without Rubberduck TestModules?


I have been using the Rubberduck VBA Add-in.

I want to "deliver" my Excel application without the Rubberduck Add-in in the References. How do you manage that? Is it possible to "hide" the TestModules and not compile them, for instance?


Solution

  • If your test modules were early-bound (which is a great idea when developing!), then you should remove the reference to the Rubberduck type library before delivering.

    Of course you could simply remove the test modules, but that becomes an annoyance of re-importing and exporting... and you don't want to do that.

    You can ship the project as-is (with the test modules, but without the reference to Rubberduck), because the test modules won't be in any execution path for the actual live code: the project won't compile, but it will still run fine (unless someone tries to invoke a test method.. then the test module(s) will be loaded, and the missing library will be noticed by the compiler).

    But my recommendation would be to go one step further and late-bind the AssertClass instance (and the FakesProvider, if you're using that API):

    Option Explicit
    Option Private Module
    
    '@TestModule
    '@Folder("Tests")
    
    Private Assert As Object
    Private Fakes As Object
    
    '@ModuleInitialize
    Private Sub ModuleInitialize()
        'this method runs once per module.
        Set Assert = CreateObject("Rubberduck.AssertClass")
        Set Fakes = CreateObject("Rubberduck.FakesProvider")
    End Sub
    
    '@ModuleCleanup
    Private Sub ModuleCleanup()
        'this method runs once per module.
        Set Assert = Nothing
        Set Fakes = Nothing
    End Sub
    

    With the tests late-bound, the project will now compile with the test modules included. Of course invoking a test method will blow up (unless Rubberduck is on that machine!), but then again the test modules shouldn't be in any execution path of your VBA project.

    You can configure Rubberduck to late-bind new test modules by default:

    Unit Test Settings

    If you're using "Permissive assert" (it implements type equality in a VBA-like permissive way), the ProgID you'll want to use for late-binding is Rubberduck.PermissiveAssertClass.

    A relatively new possible configuration, is "dual binding", which sets up new test modules as follows:

    Option Explicit
    Option Private Module
    
    '@TestModule
    '@Folder("Tests")
    
    #Const LateBind = LateBindTests
    
    #If LateBind Then
        Private Assert As Object
        Private Fakes As Object
    #Else
        Private Assert As Rubberduck.PermissiveAssertClass
        Private Fakes As Rubberduck.FakesProvider
    #End If
    
    '@ModuleInitialize
    Private Sub ModuleInitialize()
        'this method runs once per module.
        #If LateBind Then
            Set Assert = CreateObject("Rubberduck.PermissiveAssertClass")
            Set Fakes = CreateObject("Rubberduck.FakesProvider")
        #Else
            Set Assert = New Rubberduck.PermissiveAssertClass
            Set Fakes = New Rubberduck.FakesProvider
        #End If
    End Sub
    
    '@ModuleCleanup
    Private Sub ModuleCleanup()
        'this method runs once per module.
        Set Assert = Nothing
        Set Fakes = Nothing
    End Sub
    

    Configured like this, you can easily toggle between late and early binding modes:

    #Const LateBind = True '/False
    

    If you have multiple test modules, you can define a project-level precompiler constant named LateBindTests, and toggle late/early binding for all Rubberduck test modules at once. You can do this in the Project Properties (from the Tools menu, or right-click your project in the Code Explorer and select Project Properties):

    Project Properties VBIDE dialog

    (side note: the Help File project property (no one uses that, right?) is being hijacked by Rubberduck to assign and persist a unique ID to the project - changing this value without immediately saving & closing will break stuff)