In a previous post about the “VB6 problem” I wrote that salvaging business critical classic Visual Basic applications involved these steps:
- Build it
- Test it
- Change it
That post (Setting up a VB6 Environment) concerned the first step and will take you through setting up an environment which can build legacy applications using Visual Studio 6. This post starts the discussion about the second step: testing.
I’ll start by repeating a critical thing to remember about legacy code: in its current state, the legacy code supports today’s business.
Consider the case where that statement is not true. Imagine that the legacy application does not support today’s business. If this were true then it would follow that either the business is failing or the application is no longer being used.
Although the application supports today’s business, we often feel that the application could support the business better. An application could be more efficient in terms of computing or human resources by taking less time to run or interact with. We may want to capture new business by adding features. Whatever the changes and our reasons for them, we need to make these changes without breaking the current functionality, and that’s where testing comes in. We can write tests to characterize the application’s current behavior. We assume this behavior is correct because it supports today’s business. Then we make changes and re-run our tests to ensure that we haven’t broken anything in the process.
We must take this characterization step even when we don’t assume that the legacy code is “correct by default”. If we are changing the code to fix a long standing bug, we still want to know how the code behaves today. Once we have characterized the current behavior with a test, we can change the test to expect the desired behavior. Finally, we change the code to correctly express the new behavior.
Before we can apply these concepts to the specific case of salvaging classic Visual Basic code we need to know more about the testing tools available for VB6. In this post we will look at a specific unit testing tool for Visual Basic called SimplyVBUnit. SimplyVBUnit is an MIT licensed open source project, which is actively maintained (the most recent update as of this writing was April 18, 2015–not that long ago at all). There are actually a couple more unit testing frameworks for VB6, but SimplyVBUnit seems like a good way to get our feet wet.
If you followed my first guide to setting up a VB6 environment, then you will want to install SimplyVBUnit inside XP Mode. Use the
Start Menu to select
Windows Virtual PC and then
Windows XP Mode. (If you set up your environment differently, then I will trust you to install it wherever is best for your environment.)
The SimplyVBUnit project provides an installer program, so fire up IE8 and download the latest version from SourceForge. You may need to click a little warning banner to allow the download.
Once the download completes double click the installer to run. Again, you may have to click through a security warning to let XP know you really want to install.
The setup wizard is easy to use, just click
Next until the wizard completes. Unfortunately, the installer is not the end of the story.
SimplyVBUnit has a decent wiki on SourceForge. This wiki includes a page on the installation and a few on setting up tests. The installation page reads like release notes and pretty much just tells us to run the wizard. When we get to the new project instructions, the very first instruction shows a
SimplyVBUnit Project template in the VB6
New Project dialog. However, I don’t see that on my system after completing the wizard.
To see the template, you will need to take the following additional steps inside XP Mode:
- Navigate to
C:\Program Files\SimplyVBUnit 4.1\Source\Projects
- Copy all files in this folder.
- Paste these files in
C:\Program Fies\Microsoft Visual Studio\VB98\Template\Projects
Now when you start VB6, the template should appear. Close Visual Studio, then log off of XP Mode so that we can start experimenting with SimplyVBUnit.
Create Test Project
Now start VB6 as a virtualized application. Once VB6 starts, you should be able to follow along with the getting started guide on the Wiki. First, create a new
SimplyVBUnit Project. Next use the
Tools menu to select
Options, then select the
General tab in the dialog that appears. Change the
Error Trapping option to
Break on Unhandled Errors. Click
Now you can use the play button to start debugging. The SimplyVBUnit test runner will launch and you can click
Run. Your test run should indicate success, since you currently have no tests, and therefore no test failures.
Create Production Library
Although our overall goal is to learn how to salvage legacy code, our immediate goal is to learn about SimplyVBUnit. So let’s take the easy path and continue to follow along with the wiki by creating a brand new class library to test.
Stop the debugger if it is still running. Next, use the
File menu to select
Add Project..., then choose
ActiveX DLL. By default, this project will be created with the name
Project1, and contain a class called
Class1. I can’t stand such terrible names, even during a demo, so I will make up some better ones:
CoolCalculator for the project and
Calculator for the class.
With that very important step completed, we can continue by adding a reference to
CoolCalculator in the
SimplyVBUnitTesting project. Select
SimplyVBUnitTesting in the
Project Group pane, and then use the
Project menu to select
CoolCalculator should be near the top of the
Available References list, with its check box unchecked. Check the box, then click
The wiki advises us to save our work so far, and that seems like a good idea. Use the
File menu to select
Save Project Group. VB6 starts by saving each file, and by default it wants to put the files in the
VB98 folder under
Program Files. This is no good, navigate to
My Documents and create a folder called
CalculatorDemo and save your files there. You will need to save the
Calculator class, the
CoolCalculator project file, the
frmTestRunner form from SimplyVBUnit, and the
SimplyVBUnitTesting project file–also from the SimplyVBUnit template, and finally you need to save the project group file using the name
Create Test Class
Now we will create a test class and use it to drive a feature in
CoolCalculator. Right click on
SimplyVBUnitTesting in the project group, and select
Class Module. Make sure
Class Module is selected in the dialog that opens, and click
Once again, this creates a class called
Class, so rename it to
CalculatorTests. Next we will register this test class with the test runner
frmTestRunner. Right click on
frmTestRunner and select
frmTestRunner contains a stub for
Form_Load with comments that explain how to setup a test case (which we have already started). SimplyVBUnit also provides a comment demonstrating how to register a test case with the runner. Register our test case now by adding the following code to the line below the example comment:
AddTest New CalculatorTests
Now we can add a test to our test suite. Let’s make sure our calculator can add. Type the following code into the
Option Explicit Public Sub Add_Two_Numbers() Dim calc As New Calculator Dim actual As Integer actual = calc.Add(1, 1) Assert.That actual, Iz.EqualTo(2), "1 + 1 = 2" End Sub
This code creates a new
Calculator instance, uses it to add
1 to itself, then constructs a test assertion to verify the result. We can hit the play button to see what happens when we try to run this test. We expect that the test runner will try to run the test, since we registered it. We also expect that the test will fail, since
Calculator has no implementation.
As expected, the test runs then fails as predicted. If we click
Ok on the compilation error dialog, we will drop into the debugger at the beginning of the
Add_Two_Numbers method (yellow highlight). Notice also that the
.Add method is highlighted in blue.
Having verified our expectations, lets stop the debugger and add some code to the production library. Open the
Calculator class and add these lines of code:
Option Explicit Public Function Add(ByVal left As Integer, ByVal right As Integer) As Integer End Function
This code should get us past the compilation error, because it will provide the method
Add, which is expected by the test. However, we still expect the test to fail, because
Add has no body, and therefore we expect it to return the default value for integer, which is
Once again, the test runner confirms our expectations. So lets add a little more code to see if we can get the test to pass. Stop the debugger and add the following line of code to the
Add method body.
Add = left + right
Use the play button to run the test again. At this point we expect that the test should pass. The test runner confirms our expectation.
The wiki goes on to explain
Testing Multiple Scenarios, which looks to me like data driven or theory tests, depending on which jargon you prefer. That’s a nice feature, but I’ll leave its exploration as an exercise for the reader.
We are done with the
CalculatorDemo project for now, so close VB and save any changes.
In this post we used the classic Visual Basic environment that we created in Setting up a VB6 Environment to explore a native Visual Basic testing tool called SimplyVBUnit. Although the SimplyVBUnit installer did not automatically copy the testing templates for us, we were able to work our way past that problem and build an example test which we used to drive the creation of a simple calculator feature.
Although working with SimplyVBUnit was relatively simple, there are two things to consider before choosing it as the means to salvage VB6 code and make it safe to update. First, remember that the example we built for this post did not focus on characterizing legacy code. Instead, we took the easy path of creating a new project so that we could become familiar with SimplyVBUnit mechanics. Before going further, it makes sense to explore characterizing an existing code base with SimplyVBUnit. What do I even mean by characterization, and might there be pitfalls that we have not yet uncovered on the easy path?
Second, we should ask ourselves if native VB6 unit testing is the way to go. As discussed in the first Postmodern VB6 post, our goal when working with VB6 should be to get to a state where we aren’t working with VB6 anymore. If we accept that goal, and plan to migrate to a new platform, then we should seriously consider writing our tests in the new platform. After all, if we succeed in migrating, then all VB6 code will be retired, including the tests we are writing now. Furthermore, all the tests we write in VB6 will just be more code we need to convert to the new platform later. Even if we are able to figure out how to add SimplyVBUnit tests to an existing codebase, then we should still explore the possibility of using a testing tool which is native to our target platform.
Those considerations aside, it’s good to have SimplyVBUnit in our tool set, and I hope this post makes it easier to started.