I’ve blogged before about converting my FoxPro apps from application forms to the Business Object based programming approach (thereby moving away from forms based heavily on open tables, work areas, and relations). I used the West Wind wwBusiness classes to make this transformation, and it is the most exciting VFP work I have ever done. A Business Object framework like West Wind wwBusiness automatically gives you basic niceties such as methods like Load() and Save() right there on the BO to do all the back end data handling for you. This feature alone allowed me to greatly reduce the amount of code I had piled up in click events all over my *forms* for many years. No more worrying about the the record pointers, or relations, or binding my form UI controls directly to table names and fields. I promise you, once you go BO’s you’ll never go Back! (Don’t get sidetracked from this post yet, but you can read my original review of the West Wind wwBusiness library here.
Another benefit of BO classes is that you can now programmatically drive your application’s activities by making method calls into the various methods on the BO. No UI forms required… Just good old procedural code! For instance, on my Job Business Object, I have lots of methods to fetch records into a local cursor, array, or collection, as well as other methods that change or examine data on the BO, or return scalar values, etc. I started out forcing myself to test my BO’s from the command line to make sure I could manually orchestrate everything I wanted my forms to do. This would ensure that it would require very little code in the UI forms to make the app work. With all the essential code tucked away in methods on BO classes you can then basically create the same app in SCX Forms, or web frameworks, or just good old procedural programming in various PRGs. Plus, the ease of maintenance improves greatly, since all your code lives in one class, rather that splashed all over the place inside a form.
So I’ve had this vision, after hearing more and more about all this “Test First” buzz in other coding circles like .Net and Rails, that I could write a suite of PRGs that serve as tests I can run at any time on my entire collection of BO’s. This allows me to immediately test every BO in my library any time I make code changes anywhere in the class hierarchy, or even if the table schemas changed too. I can’t tell you how many times I’ve made low level changes in the base classes, or added a new top level method to a concrete class, or changed a field name in a table, and the only real way I’ve had to test the changes is to throw out a beta version of the app, and drive it around like a real user to see if it works correctly, or has errors.
And shown below is a sample of the test code I have written which creates a Job Business Object, and then tests a particular method (the GetActiveJobs() method in this example). You’ll see in the comment that this method can accept up to 5 parameters, so I’ve written tests for many possible combinations of parameters and values. Even with this many test calls, I’m sure there are a few combinations that I may have missed. This shows how tedious a full test suite can become. In this testing approach, you basically *TRY* to break your code by passing in every possible combination of parameters that these business classes might see in real application usage. Remember, you want to write these classes with the idea that you or someone on your team will be working with these classes for years, you simply expect them to work without knowing all the do’s and don’ts about calling into these methods.
What you don’t see here is that the test method calls likes BeginningOfTest(), TestProgress(), and EndOfTest(), record logging info to a results file that I can then review to study the return values, processing time, etc.
Now, the bad thing is that if I complete this exercise, there are perhaps 20 or more methods that I must write tests for, and that’s just on the Job Business Object. Then I’ll have to tackle all the other Business Objects in my libraries (PurchaseOrder object, Quote object, Part object, etc. About 15 Business Objects in all). So this is no trivial amount of work, and you have to remember to write a test for every new method you add to a Business Object, otherwise, you’re letting the thing fall apart. It’s very easy to look at your code and think you’ve got everything or every situation covered, but certainly creating a formal test suite for your classes will help identify problems before you take your app to production. Oh, you’ll also notice that CreateWWBO() is a factory method that returns a Business Object based on the passed key, so there’s some other coding in my architecture that resolves this tag and the class name as well as the class library.
And here is the output to the log file. If there were any errors returned from the Business Object, or if the return results were not the expected results, then I’d see reporting to this effect in the log file. Now, there is some coupling here between these tests and test data that I’m running against, so the test could appear to break if some of the test data changed, so this is no magical solution and requires some attention to this detail when preparing and running these tests. To me, the main effort is to find broken code in the classes given a predictable data set.
This is just one code sample. I have other tests that test the basic Load(), New(), Save(), and Delete() methods as well.