patternModerate
Automagic testing framework for VBA
Viewed 0 times
automagictestingforvbaframework
Problem
Building on @RubberDuck's recommendations, I now have something I find... beautiful. I'm sure there's a couple of things left to polish - this site is about making great code out of good any code, right?
This code requires trusted programmatic access to Visual Basic Project.
I want my test classes to look like this:
TestClass1 class module (client code)
Output
I want to be able to run my tests from a simple "command-line" call in the immediate pane:
`TestEngine.RunAllTests "VBAProject", New TestClass1
Registered test: TestClass1.MagicCommentWorks
Registered test: TestClass1.TestAreEqual
Registered test: TestClass1.TestAreNotEqual
Registered test: T
This code requires trusted programmatic access to Visual Basic Project.
- Client Code
I want my test classes to look like this:
TestClass1 class module (client code)
Option Explicit
Public Sub ThisIsNoTest()
Err.Raise 5
End Sub
'@TestMethod
Public Sub MagicCommentWorks()
End Sub
Public Sub TestAreEqual()
assert.AreEqual 12, 12, "Values should be equal."
End Sub
Public Sub TestAreNotEqual()
assert.AreNotEqual 12, 34, "Values should not be equal."
End Sub
Public Sub TestAreSame()
assert.AreSame New Collection, New Collection, "Objects should be same reference."
End Sub
Public Sub TestAreNotSame()
assert.AreNotSame New Collection, New Collection, "Objects should not be the same reference."
End Sub
Public Sub TestFail()
assert.Fail "This wasn't meant to be."
End Sub
Public Sub TestInconclusive()
assert.Inconclusive "No idea."
End Sub
Public Sub TestIsFalse()
assert.IsFalse False, "True should be False."
End Sub
Public Sub TestIsNothing()
Dim foo As Object
assert.IsNothing foo, "Foo should be nothing."
End Sub
Public Sub TestIsNotNothing()
Dim foo As New Collection
assert.IsNotNothing foo, "Foo shouldn't be nothing."
End Sub
Public Sub TestIsTrue()
assert.IsTrue True, "False should be True."
End Sub
Public Sub TestBlowUp()
assert.IsTrue True
assert.AreEqual False, True
Debug.Print 1 / 0
assert.Fail "Test should have failed by now."
End Sub
Public Sub TestNoAssert()
End SubOutput
I want to be able to run my tests from a simple "command-line" call in the immediate pane:
`TestEngine.RunAllTests "VBAProject", New TestClass1
Registered test: TestClass1.MagicCommentWorks
Registered test: TestClass1.TestAreEqual
Registered test: TestClass1.TestAreNotEqual
Registered test: T
Solution
Look what I found
Personally I don't like declaring variables like this, and almost every language allows you to do this in some way or another.
I think this is one of those holy war issues though, some programmers like doing this and some programmers say this is bad practice.
Be wary of who is going to maintain this code and what they will say about you when you are gone.
I found something else, probably left overs of changing code or logic
I am guessing that you don't need
anymore and that it was leftover, although I think that you would want something like this instead
So that if you exit the function in one of your if statements it says "hey I am false, you can't add a test method"
but then I remember that we are talking about VBA here and I think that if you exit without setting the method it will automagically be false, so it would be just
In the
I am not sure that this was on purpose or not, maybe the Error Description won't work if the GoTo is earlier and there is an error before the 3rd line.
Just a thought.
Can we move the
It would be seen easier when debugging the code
instead of This
write it like this
And Where are all the Brackets and Semi-Colons?
Dim procedureName As String, lastFound As String
Dim procedureBody As StringPersonally I don't like declaring variables like this, and almost every language allows you to do this in some way or another.
I think this is one of those holy war issues though, some programmers like doing this and some programmers say this is bad practice.
Be wary of who is going to maintain this code and what they will say about you when you are gone.
I found something else, probably left overs of changing code or logic
Private Function CanAddTestMethod(ByVal prospect As Method, ByRef testMethods As Dictionary) As Boolean
Dim result As Boolean
If Not IsTestMethodName(prospect) Then Exit Function
If testMethods.Exists(prospect.name) Then Exit Function
CanAddTestMethod = True
End FunctionI am guessing that you don't need
Dim result As Booleananymore and that it was leftover, although I think that you would want something like this instead
Private Function CanAddTestMethod(ByVal prospect As Method, ByRef testMethods As Dictionary) As Boolean
CanAddTestMethod = false
If Not IsTestMethodName(prospect) Then Exit Function
If testMethods.Exists(prospect.name) Then Exit Function
CanAddTestMethod = True
End FunctionSo that if you exit the function in one of your if statements it says "hey I am false, you can't add a test method"
but then I remember that we are talking about VBA here and I think that if you exit without setting the method it will automagically be false, so it would be just
Private Function CanAddTestMethod(ByVal prospect As Method, ByRef testMethods As Dictionary) As Boolean
If Not IsTestMethodName(prospect) Then Exit Function
If testMethods.Exists(prospect.name) Then Exit Function
CanAddTestMethod = True
End FunctionIn the
RunTest sub you wait until the third line of code to declare the error handling, I am not sure that this was on purpose or not, maybe the Error Description won't work if the GoTo is earlier and there is an error before the 3rd line.
Just a thought.
Can we move the
Exit Function code in the GetMethods function to the start of the function so we don't have to Dim variables we aren't going to use?It would be seen easier when debugging the code
instead of This
Public Function GetMethods(ByVal projectName As String, ByVal className As String) As List
Dim result As List
Set result = List.Create
Dim procedureName As String, lastFound As String
Dim procedureBody As String
Dim proj As VBProject
Set proj = GetProject(projectName)
If proj Is Nothing Then Exit Function
Dim module As CodeModule
Set module = GetClass(proj, className)
Dim i As Long
For i = module.CountOfDeclarationLines + 1 To module.CountOfLines
procedureName = module.ProcOfLine(i, vbext_pk_Proc)
If procedureName <> lastFound Then
procedureBody = module.Lines(module.ProcStartLine(procedureName, vbext_pk_Proc), module.ProcCountLines(procedureName, vbext_pk_Proc))
result.Add Method.Create(procedureName, procedureBody)
lastFound = procedureName
End If
Next
Set GetMethods = result
End Functionwrite it like this
Public Function GetMethods(ByVal projectName As String, ByVal className As String) As List
Dim proj As VBProject
Set proj = GetProject(projectName)
If proj Is Nothing Then Exit Function
Dim result As List
Set result = List.Create
Dim procedureName As String, lastFound As String
Dim procedureBody As String
Dim module As CodeModule
Set module = GetClass(proj, className)
Dim i As Long
For i = module.CountOfDeclarationLines + 1 To module.CountOfLines
procedureName = module.ProcOfLine(i, vbext_pk_Proc)
If procedureName <> lastFound Then
procedureBody = module.Lines(module.ProcStartLine(procedureName, vbext_pk_Proc), module.ProcCountLines(procedureName, vbext_pk_Proc))
result.Add Method.Create(procedureName, procedureBody)
lastFound = procedureName
End If
Next
Set GetMethods = result
End FunctionAnd Where are all the Brackets and Semi-Colons?
Code Snippets
Dim procedureName As String, lastFound As String
Dim procedureBody As StringPrivate Function CanAddTestMethod(ByVal prospect As Method, ByRef testMethods As Dictionary) As Boolean
Dim result As Boolean
If Not IsTestMethodName(prospect) Then Exit Function
If testMethods.Exists(prospect.name) Then Exit Function
CanAddTestMethod = True
End FunctionDim result As BooleanPrivate Function CanAddTestMethod(ByVal prospect As Method, ByRef testMethods As Dictionary) As Boolean
CanAddTestMethod = false
If Not IsTestMethodName(prospect) Then Exit Function
If testMethods.Exists(prospect.name) Then Exit Function
CanAddTestMethod = True
End FunctionPrivate Function CanAddTestMethod(ByVal prospect As Method, ByRef testMethods As Dictionary) As Boolean
If Not IsTestMethodName(prospect) Then Exit Function
If testMethods.Exists(prospect.name) Then Exit Function
CanAddTestMethod = True
End FunctionContext
StackExchange Code Review Q#63004, answer score: 12
Revisions (0)
No revisions yet.