Planning a Code Component

As I said at the beginning, the most important concept that I want this chapter to convey is the necessity of writing testable code. Less experienced Visual Basic programmers have a tendency to implement a lot of functionality directly beneath command buttons. I've certainly seen instances where there are several hundred lines of code behind a button: code that updates the screen, displays and processes the results from a File Open dialog box, reads from the registry, performs a database access, and then writes to the screen again. I've even seen code like this that exists in two places: behind a command button and again underneath a menu item. (Cut and paste can be such a useful facility.)

When you write a piece of code it needs to be as function-specific as possible. Therefore the monolithic code block that I've just described should be broken down into small routines. First of all there should be very little code behind a button—ideally, a call to another routine, but a small number of relatively safe commands is acceptable. If there is a need for a large amount of processing, there should be one procedure that controls the overall flow and control of the process, and that procedure calls function-specific routines. In the description I gave above, the database access should be a separate routine, as should the Registry code, and so on. This is good practice, and there is no taboo in having many small private routines attached to a form, a module, a class, or whatever.3 The testing is so much easier this way, and it also makes for much more specific error handling code. It's also tidier, of course.

It's important not to get too formal with the coding, though; we'd never get it delivered. The code that goes into making a Microsoft Windows application can be divided into two categories: process specific and interface specific. In very general terms4 the test code that goes into the process-specific sections is what needs to be planned beforehand because it's the process that actually gets the user's work done. The interface-specific elements of the system are still important, but they demand a much greater degree of spontaneous interaction from the user.

To illustrate the planning process I have invented the following functional specification for a small DLL, and I have included an associated test plan.5 Most real-world requirements will be more comprehensive than this but I don't feel that additional detail would add any extra weight to the point that I'm trying to get across. All software should be written from a functional specification (or design document, if you prefer). However, you'll find that if you write the test plan at the same time as (or immediately after) the functional specification, you will continually identify test scenarios that will prompt you to go back to the functional specification to add necessary error handling directives. This happened to me while I was writing the test script specification for the example DLL, even though it's only a simple demonstration.

Functional Specification

Create a prototype ActiveX DLL component (SERVERDATA.DLL) that encapsulates the StockList table of the SERVERDATA.MDB database. The table is defined as shown on the following page.

Field name Data Type Description
ID AutoNumber ID number for each record
StockCode Text (length = 8) Stock code to identify item
Name Text (length = 50) Name of stock item
StockLevel Number (Long Integer) Number of units currently held
UnitPrice Currency Price of each unit

General requirements

The following characteristics should be defined for the DLL component:

  1. The DLL component does not explicitly need any startup code.

  2. The DLL component should have two classes defined.

    • CStockList, which provides a logical wrapper around the StockList table. Its Instancing property should be set to MultiUse.

    • CStockItem, which acts as a single record representation of the StockList table. Its Instancing property should be set to PublicNotCreatable.6

  3. Database access should be performed via ActiveX Data Objects (ADO).

  4. The database should be opened during the first call upon it, and should be closed during the Terminate event of the CStockList class. For the purposes of this prototype it can be assumed that the client application will not generate any database activity from the CStockItem class once the CStockList class has been destroyed.

CStockList

Implement the following interface:

Add method Input parameters:

      StockCode As String      Name As String      StockLevel As Long      UnitPrice As Currency 

This method should create a new record in the StockList table and populate that record with the parameter data. It should check that the StockCode value has not already been used and that all numeric values are at least zero. (If there is an error, a negative value is returned.)

Count property (read-only) This property should return the number of records in the StockList table.

Item method function Input parameters:

      StockCode As String 

This function should create, instantiate, and return an object of type CStockItem for the record identified by the StockCode parameter. This function should raise an error in the event of the record not being found.

ItemList function Input parameters:

      None 

This function should return a collection of all StockCode values that exist within the StockList table.

StockValue property (read-only)This property should return the sum of each record's StockLevel field multiplied by its UnitPrice field.

Remove method Input parameters:

      StockCode As String 

This method should delete the record that matches the supplied StockCode value.

CStockItem

Implement the following interface:

Name property (read/write) Let/Get for the Name field.

StockCode property (read/write) Let/Get for the StockCode field.

StockLevel property (read/write) Let/Get for the StockLevel field.

UnitPrice property (read/write) Let/Get for the UnitPrice field.

StockValue property (read-only) Get property only. Calculated dynamically and is the product of the UnitPrice field and the StockLevel field.

Update method This method should apply any changes that are made to any of the read/write properties.

Test Script Specification

(The idea here is that we want to methodically check each member of the public interface. Some of the test routines will automatically make use of some of the other members.)

Objective: To ensure that each member in the CStockList and CStockItem classes have been run at least once to ensure correct behavior. This is a component-level test that will be performed by the development team.

Test methodology: The two classes are implemented in an ActiveX DLL. This allows for the creation of a dedicated test harness application that will act as a normal client program. For this initial test, sample data will be hard-coded into the test harness application. (The possibility exists to extend this in the future so that test data will be read from a data file.)

Scope of this strategy: This is a generic document that outlines a method of testing without providing any test data. Reasonable test data can be created as required.

Test environment: Windows 98 (full installation), run-time files as installed by Visual Basic 6. No service packs are applied to these products at this time.

SERVERDATA.DLL test 1

Members used: Add, Count, Item, StockValue

Intent: Check that a record is added successfully.

  1. Formulate the data for a new record that doesn't already exist in the table.

  2. Create a reference to a CStockList object.

  3. Call the Item method using the new StockCode value (from step 1) and verify that this raises a "not found" error. This is to check that the record doesn't already exist. If it does exist, this test data has already been used and so the rest of the test should be aborted.

  4. Call the Count property. Check that this tallies with the number of records currently in the table (via Access?).

  5. Call the StockValue property to establish the value Y of total stock currently held.

  6. Calculate the value X of the new item of stock that is to be added by multiplying the StockLevel value with the UnitPrice value.

  7. Call the Add method with the new stock data.

  8. Call the StockValue property and verify that it is equal to the value of X + Y.

  9. Call the Item function to obtain a reference to a CStockItem object. Verify that each property matches the original data. Release the reference to the CStockItem object.

  10. Release the reference to the CStockList object.

SERVERDATA.DLL test 2

Members used: Add

Intent: Prove that a new record with a duplicate key value will be rejected.

  1. Create a reference to a CStockList object.

  2. Attempt to add a record that already exists. A predictable error should be raised (that is, client error handler should include a check for this specific error code being raised).

  3. Release the reference to the CStockList object.

SERVERDATA.DLL test 3

Members used: Remove

Intent: Check that an attempt to delete a record that doesn't exist will fail gracefully.

  1. Create a reference to a CStockList object.

  2. Attempt to remove a record that doesn't exist. A predictable error should be raised.

  3. Release the reference to the CStockList object.

SERVERDATA.DLL test 4

Members used: Item, Update

Intent: Prove that the CStockItem.Update method will reject an attempt to modify a record where the StockCode value would be the same as an existing record.

  1. Create a reference to a CStockList object.

  2. Attempt to rename a StockCode value to an existing value. A predictable error should be raised.

  3. Release the reference to the CStockList object.


Ltd Mandelbrot Set International Advanced Microsoft Visual Basics 6. 0
Advanced Microsoft Visual Basic (Mps)
ISBN: 1572318937
EAN: 2147483647
Year: 1997
Pages: 168

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net