9

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?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Ben
  • 93
  • 3
  • Seems to me all you need to do is remove the test module(s). I don't think there is a reference to RD in the Tools>References. – SmileyFtW Nov 08 '19 at 16:18
  • @SmileyFtW that would work, but isn't necessary (plus it then becomes a PITA to export/re-import them for maintenance & deployment) – Mathieu Guindon Nov 08 '19 at 16:20
  • @MathieuGuindon - Agree it would be a PITA, but if the distributed code gets updated, wouldn't it be from the one in the developer's system and not the user's and an updated one would not depend on one that has been distributed to a user? Of course, a user would then not be able to see the marvelous things RD does.... – SmileyFtW Nov 08 '19 at 16:56
  • @SmileyFtW in theory, yes.. in practice.... VBA maintenance and deployment isn't exactly standardized :) – Mathieu Guindon Nov 08 '19 at 16:57
  • 1
    Excellent question. Starred for future reference – FreeMan Nov 08 '19 at 17:51

1 Answers1

8

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)

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • 1
    FWIW, if you want to have a global switch because you have multiple test modules, you can define the flag in the project's properties (via the Debug menu). – this Nov 08 '19 at 16:33
  • @MathieuGuindon Great answer ! I knew there was something around late binding ... My mistake was to chip it with early binding and without removing the rubberduck references ... Thank you ! – Ben Nov 08 '19 at 17:15