Objects First


Class Design - Verifying the Dictionary Class

  1. Testing the Class

    First we'll develop a small program to informally test the methods of the Dictionary class. We'll do that to illustrate some file I/O routines and to develop a method for loading a dictionary from a file.

    Then we'll examine the problem of formally testing the class methods.

    Click here to load the first test program.

  2. Prologue and header

    As usual, we have a prologue, import statements and some constants defined for this program.

  3. Tool building

    To test this class, we decided to put a test dictionary in a data file and write a function to load this dictionary into the dictionary object in our program.

    So we started writing this program by writing some software tools - functions that encapsulated a set of useful operations (reading and parsing lines from the file and loading them into the dictionary) into one function. This has the effect of making the main function extremely simple and easy to understand.

    There are two of these tool routines here, ParseLine which parses the input line into its constituent words, and LoadDictionary which opens the file, reads lines, calls ParseLine to parse them and then adds the words to the dictionary.

    For the moment, let's skip over ParseLine to LoadDictionary.

  4. LoadDictionary

    The specification for this function is just like any other method on the Dictionary class:
    int LoadDictionary( Dictionary d, char *file_name );
    
    We've added assert's to the function to check pre-conditions - even though we haven't bothered to provide a formal specification of this function as we would do for a class method, we don't abandon our good robust programming habits and leave the assert's behind! In fact there's no reason why we couldn't move it into the class itself as a method that loads a dictionary from a file - a perfectly legitimate class method!

    Working through this function, line by line --
    after the asserts, we initialise the count of words added to the dictionary to 0.

    Then we try to read the file, we've put the words and their translations in a text file (we prepared it with a text editor), so we use the stream I/O routines, fopen, fclose, fgets, ... The file's name is in the string, file_name, passed as an argument, so we pass it to fopen along with a second argument, "r", which tells fopen that we want to read the file. If fopen can open the file for us, it will return a file handle of type FILE *, which we store in the variable, f. Remember that we can consider fopen as a constructor for the input stream of data from the file. It returns an object (the data stream) that we can manipulate with fgets, etc.

    If the file doesn't exist or can't be read, or any other system error occurs, then fopen will return a NULL. In this case, we jump to the else branch of this if and print a suitable message.

    The translations are stored in the file one translation (English word; foreign word) to a line. Therefore we use fgets to read lines one at a time into the buffer buf. Note how we carefully used a symbolic constant, BUF_LEN, to declare the array: char buf[BUF_LEN] and here in the call to fgets.

    If fgets tries to read past the end of the file, it will return a NULL. So the while( fgets(..) != NULL ) loop conveniently reads lines from the file, one by one, and exits from the loop at the end of the file.

  5. Verify the class

    Now we need to construct at least one program to verify that the class is correct:

Continue on to Verifying the Dictionary Class
Back to the Table of Contents
© John Morris, 1998