I recently started learning C# and am taking the opportunity to try and accelerate my introduction by helping the RubberDuck team (Website and GitHub Repo). The full class code that I'm working on can be found here. Its purpose is to create a Module in VBA that will allow unit testing.
Since
FakesFieldDeclarationFormat
andAssertFieldDeclarationFormat
are used only once would it be better to move them to just above where they are fed intoDeclarationFormatFor
?Would it be better to migrate
FolderAnnotation
intoTestModuleEmptyTemplate
since whenformattedModuleTemplate
is created that is ultimately what is happening?Does anyone have any suggestions for improving the names?
Anything else that help improve the code and that may assist me in learning is welcome.
The main code in question is below.
private const string TestModuleEmptyTemplate = "'@TestModule\r\n{0}\r\n{1}\r\n{2}\r\n\r\n";
private const string FolderAnnotation = "'@Folder(\"Tests\")\r\n";
private const string FakesFieldDeclarationFormat = "Private Fakes As {0}";
private const string AssertFieldDeclarationFormat = "Private Assert As {0}";
private readonly string _moduleInit = string.Concat(
"'@ModuleInitialize\r\n",
"Public Sub ModuleInitialize()\r\n",
$" '{RubberduckUI.UnitTest_NewModule_RunOnce}.\r\n",
" {0}\r\n",
" {1}\r\n",
"End Sub\r\n\r\n",
"'@ModuleCleanup\r\n",
"Public Sub ModuleCleanup()\r\n",
$" '{RubberduckUI.UnitTest_NewModule_RunOnce}.\r\n",
" Set Assert = Nothing\r\n",
" Set Fakes = nothing\r\n",
"End Sub\r\n\r\n"
);
private readonly string _methodInit = string.Concat(
"'@TestInitialize\r\n"
, "Public Sub TestInitialize()\r\n"
, " '", RubberduckUI.UnitTest_NewModule_RunBeforeTest, ".\r\n"
, "End Sub\r\n\r\n"
, "'@TestCleanup\r\n"
, "Public Sub TestCleanup()\r\n"
, " '", RubberduckUI.UnitTest_NewModule_RunAfterTest, ".\r\n"
, "End Sub\r\n\r\n"
);
private const string TestModuleBaseName = "TestModule";
private string GetTestModule(IUnitTestSettings settings)
{
var assertType = string.Format("Rubberduck.{0}AssertClass", settings.AssertMode == AssertMode.StrictAssert ? string.Empty : "Permissive");
var assertDeclaredAs = DeclarationFormatFor(AssertFieldDeclarationFormat, assertType, settings);
var fakesType = "Rubberduck.IFake";
var fakesDeclaredAs = DeclarationFormatFor(FakesFieldDeclarationFormat, fakesType, settings);
var formattedModuleTemplate = string.Format(TestModuleEmptyTemplate, FolderAnnotation, assertDeclaredAs, fakesDeclaredAs);
if (settings.ModuleInit)
{
var assertBinding = InstantiationFormatFor(assertType, settings);
var assertSetAs = $"Set Assert = {assertBinding}";
var fakesBinding = InstantiationFormatFor(fakesType, settings);
var fakesSetAs = $"Set Fakes = {fakesBinding}";
formattedModuleTemplate += string.Format(_moduleInit, assertSetAs, fakesSetAs);
}
if (settings.MethodInit)
{
formattedModuleTemplate += _methodInit;
}
return formattedModuleTemplate;
}
private string InstantiationFormatFor(string type, IUnitTestSettings settings)
{
const string EarlyBoundInstantiationFormat = "New {0}";
const string LateBoundInstantiationFormat = "CreateObject(\"{0}\")";
return string.Format(settings.BindingMode == BindingMode.EarlyBinding ? EarlyBoundInstantiationFormat : LateBoundInstantiationFormat, type);
}
private string DeclarationFormatFor(string declarationFormat, string type, IUnitTestSettings settings)
{
return string.Format(declarationFormat, settings.BindingMode == BindingMode.EarlyBinding ? type : "Object");
}
The final output for VBA:
Early Binding:
Option Explicit
Option Private Module
'@TestModule
'@Folder("Tests")
Private Assert As Rubberduck.AssertClass
Private Fakes As Rubberduck.IFake
'@ModuleInitialize
Public Sub ModuleInitialize()
'this method runs once per module.
Set Assert = New Rubberduck.AssertClass
Set Fakes = New Rubberduck.IFake
End Sub
'@ModuleCleanup
Public Sub ModuleCleanup()
'this method runs once per module.
Set Assert = Nothing
Set Fakes = Nothing
End Sub
'@TestInitialize
Public Sub TestInitialize()
'this method runs before every test in the module.
End Sub
'@TestCleanup
Public Sub TestCleanup()
'this method runs after every test in the module.
End Sub
Late Binding:
Option Explicit
Option Private Module
'@TestModule
'@Folder("Tests")
Private Assert As Object
Private Fakes As Object
'@ModuleInitialize
Public Sub ModuleInitialize()
'this method runs once per module.
Set Assert = CreateObject("Rubberduck.AssertClass")
Set Fakes = CreateObject("Rubberduck.IFake")
End Sub
'@ModuleCleanup
Public Sub ModuleCleanup()
'this method runs once per module.
Set Assert = Nothing
Set Fakes = Nothing
End Sub
'@TestInitialize
Public Sub TestInitialize()
'this method runs before every test in the module.
End Sub
'@TestCleanup
Public Sub TestCleanup()
'this method runs after every test in the module.
End Sub
Set Fakes = New Rubberduck.IFake
should beSet Fakes = New Rubberduck.FakesProvider
, declared asIFakesProvider
- anIFake
would be e.g.MsgBoxFake
, and we don'tNew
up an interface just like that anyway. \$\endgroup\$