A Test Form

[Previous] [Next]

Before you make your test stub available to GUI developers, you should test it yourself. At least, you should create a test form. Let's build one together, one step at a time, to see whether our test stub code works as we expect.

You already have a sketch of your form. Figure 5-9 displayed this form, and for your convenience we repeat it here in Figure 6-14 as your new starting point.

Figure 6-14. Copy of the screen layout from Figure 5-9.

Getting a List of Horses

First let's add a command button to get the list of horses and then add an invisible3 ADO data control to hold the recordset your facade object will return. You should also clear the Text property of the txtNamePattern text box and the dlstHorseNames data list control.

The code should declare and create an instance of the facade class. Then it should call that instance's GetHorseList method and move the recordset to the ADO data control. Figure 6-15 displays the result you want in your test form.

Figure 6-15. The facade test stub has returned the names and IDs of two horses.

In the next several paragraphs, we'll show (and talk about) the code you need to achieve the result shown in Figure 6-15.

Declaring the facade object variable

On a module level, the objFacade variable is declared:

Private objFacade As RaceMaintFacades.fcdHorseMaint

Creating the object

The facade object is created at the Form_Load event. We use the COM mechanisms (the CreateObject function) rather than the special Visual Basic mechanism (the New keyword) to create the object. If the facade class is eventually installed into an MTS package, using COM mechanisms when creating objects is vital.4

Private Sub Form_Load() Set objFacade = CreateObject("RaceMaintFacades.fcdHorseMaint") End Sub

Reacting to a click

The following code reacts when the user clicks the cmdGetHorseList command button:

Private Sub cmdGetHorseList_Click() GetHorseList End Sub

As always (almost), we refrain from putting procedural code in event procedures. We prefer to set up well-named procedures and call them from the event procedure. In this case, we call the GetHorseList method.

Fetching and displaying the horses

The GetHorseList method is defined as follows:

Private Sub GetHorseList() Set adcHorseList.Recordset = _ objFacade.GetHorseList(txtNamePattern.Text) End Sub

As you can see, the method calls the facade object's GetHorseList method, sending it the name pattern entered by the user. Then the method saves the recordset returned from the facade into the adcHorseList control. As a result, the form uses its list control to display the names of the two horses we hard-coded into the recordset.

Getting a Single Horse

Our next mission is to create the code we need to display more information about one of these horses when the user clicks its name in the list.

Reacting to a click

The following code reacts to a click in the horse list by calling the GetHorseById method in the form:

Private Sub dlstHorseNames_Click() GetHorseById End Sub

Fetching and displaying the horse

The GetHorseById code is just as simple as all the other code segments we've created so far:

Private Sub GetHorseById() Dim lngId As Long adcHorseList.Recordset.AbsolutePosition = _ dlstHorseNames.SelectedItem lngId = adcHorseList.Recordset!HorseId Set adcHorse.Recordset = objFacade.GetHorseById(lngId) End Sub

The first line of code synchronizes the recordset with the list control by making the right record current. Since both the recordset's AbsolutePosition and the list control's SelectedItem properties are 1-based, synchronizing the two is as simple as making the value of Recordset.AbsolutePosition equal to the value of DataList.SelectedItem.

When the right record is current, it's easy to save the ID of the selected horse to the lngId variable.

The next line calls the facade object's GetHorseById method, giving it the ID of the selected horse to work with. Then it saves the recordset returned to the adcHorse ADO data control. Because all the form fields designed to display data about a single horse are bound to the recordset, the form immediately displays data about the horse.

That's all there is to it. Figure 6-16 now displays detailed information about the horse named Nijinsky II.

Figure 6-16. The form now displays test information about one of the greatest racehorses ever.

This information is totally false, but what the heck? It's only there to prove the concept. When we get in touch with the database, will the facade object work? Will it perform all the services needed for the GUI developers to create a good user interface? Those are examples of the questions we should ask now, before we deliver this prototype to GUI developers, allowing them to create a nice user interface prototype to show their customers.

NOTE
Before we do that, just let me (Sten) tell you, that Nijinsky II wasn't bred in the United States at all. He was a male horse, so the h for sex is right, but he was born long before 1988.

He was one of the greatest racehorses ever, and I saw him the first time he, as a three-year-old, met older world-class horses. The distance was 2400 meters. At 600 meters from the goalpost, he was dead last.

At this point, I was a bit disappointed—I had expected more from him. Then I heard a voice from a couple of rows up the grandstand saying, "Lester hasn't moved yet!" As my ears heard this, my eyes saw Lester Piggott mildly ask his horse for a move.

One hundred meters later, Nijinsky II had already left all the other great stars far behind him.5

First Design Validation

Looking at the form, you can see a need for at least three possible improvements:

  • The user should be able to use a list to find the country in which the horse was bred rather than having to enter the country code manually. This would be a great help to the user, but the facade class doesn't support it. You should improve the facade class by adding a method that returns a recordset containing all countries wherein new horses might be bred. This solution would work quite well because this set of countries is and always will be rather small.
  • Likewise, the user should be able to select the sex of the horse from a list rather than typing it. Since there are only three values for sex, you can hard-code this into the user interface without having to bother the facade object.
  • Furthermore, the user should be able to select the trainer of the horse by name rather than by typing in the code. This, of course, requires that the facade class publish a method for fetching trainer names. The question is, should it fetch the names of all trainers or just a subset of them?
  • Looking in our database, we see that there are only a couple hundred trainers, so we could easily fetch them all. But if the system is likely to be used in a country such as England, France, Japan, or the United States, the number of trainers might be much larger. Perhaps the system should offer users the ability to define a selection of trainers and fetch that selection only.

To support all these scenarios, we should probably make it possible to define a selection but also to define the full set. We'll go on to make these improvements, but that's not the real point here. The important lessons to learn are the following:

  • Our overall design pattern allows the UI objects that support a use case to communicate with one facade object only. (At least, this will be the most common scenario.)
  • The facade object effectively isolates the user interface from the rest of the object model, making user interface development much easier.
  • Because of this isolation, you can turn a first version of a facade class into a test stub, allowing yourself to validate the design of the facade class. Will it do whatever the client application will want it to do?
  • After you have validated and possibly improved the facade class, you can (as a server application developer) deliver the test stub to user interface developers.
  • The UI developers in turn can validate your facade design, finding out whether they think you have thought of everything they would need the facade object to do.
  • The UI developers can also create a very early and at least somewhat living user interface, drawing on the facade prototype's functionality. They can show this UI prototype to users, allowing users to find out whether their expectations are likely to be met.

As a result of all this work, there's a good chance that users will be happier with what they finally get.

  • Users will have a positive attitude over the entire life cycle of the project.
  • Time to market will be considerably shorter because almost everything can start earlier.

Enhancing the Facade and the Test Form

To enhance the facade and the test form, you need to add some code in the facade class as well as in the test form. You must also add or replace some visible objects in the test form. Here goes.

Adding some visible objects

Let's start with the easiest part, adding two ADO data controls to the test form and replacing three text boxes with combo boxes.

  • The first ADO data control, adcTrainerList, holds a recordset containing all the selected trainers. In your test form, you select all trainers—that is, you don't use the facility to define a subset of them. That facility, however, will be in the facade class.
  • The second ADO data control, adcCountries, holds a recordset containing all countries.
  • We're adding a data combo control to the form to help select the horse's trainer. Its RowSource property will refer to the adcTrainerList ADO data control, and it will list the names of the trainers. Its DataSource property will, as did the text box it replaces, refer to the adcHorse ADO data control. Its DataField property will refer to the TrainerId field in the adcHorse data control. In other words, this data combo control will display the trainer's name, but it will send his or her TrainerId to the database.
  • We'll add another data combo control for the names of the countries in which horses might be bred. This combo box will refer to the adcHorse ADO data control in its DataSource property, and it will get its rows from the adcCountries data control.
  • We'll also add an ordinary list box to the form, and we'll bind it to the adcHorse data control. Its List property values will be h, v, and s for the sex categories a horse could belong to.
  • That's it. Figure 6-17 shows the enhanced test form in use.

    Figure 6-17. The enhanced test form uses different kinds of combo boxes to help the user select information rather than having to type it.

Adding code to the facade class

The facade class now needs two new methods: one to create a list of countries and another to create a list of trainers. Both of them resemble the GetHorseList method more than a little—or at least they will as long as they contain only test stub code. The method that composes a list of countries is the easier one to create because it doesn't accept any arguments. Since the number of countries always will be manageable, the GetCountryList method returns them all.

Our test stub code for these methods looks like this:

Public Function GetCountryList() As Recordset Dim rs As ADOR.Recordset Set rs = CreateObject("ADOR.Recordset") rs.Fields.Append "CountryCode", adVarChar, 3 rs.Fields.Append "Country", adVarChar, 20 rs.Open rs.AddNew rs!CountryCode = "USA" rs!Country = "USA" rs.AddNew rs!CountryCode = "GB" rs!Country = "Great Britain" rs.AddNew rs!CountryCode = "SWE" rs!Country = "Sweden" Set GetCountryList = rs End Function

There's nothing to explain in this code. It just returns a list of countries, each country represented by a country code and a country name. To make things more interesting when running the test form, we took the opportunity to change the GetHorseById method just a little bit. We made the code appoint a different BredIn country to each of the two horses. Here's that little code snippet only:

 Case 10 rs!HorseName = "Nijinsky II" rs!BredIn = "GB" rs!Trainer = 16 Case 20 rs!HorseName = "Nearco" rs!BredIn = "USA" rs!Trainer = 20

The GetTrainerList function is almost the same as the GetCountryList method. As you would expect, it returns different fields—trainers instead of countries—and it takes an optional argument we don't pay any attention to in the test code. Even though the GetTrainerList method is different in these respects, its structure and its behavior are almost the same:

Public Function GetTrainerList _ (Optional ByVal strLastNamePattern As String) As Recordset Dim rs As ADOR.Recordset Set rs = CreateObject("ADOR.Recordset") rs.Fields.Append "TrainerId", adInteger, 4 rs.Fields.Append "TrainerName", adVarChar, 40 rs.Open rs.AddNew rs!TrainerId = 16 rs!TrainerName = "Kahn, Michael" rs.AddNew rs!TrainerId = 20 rs!TrainerName = "Gustafsson, Tommy" Set GetTrainerList = rs End Function

Adding code to the test form

We need to add code to the test form to call a method that fetches and displays trainers in the proper combo box. We also need a method to fetch and display countries in another combo box:

Private Sub Form_Load() Set objFacade = CreateObject("RaceMaintFacades.fcdHorseMaint") GetTrainerList GetCountryList End Sub

We also have to implement both of these methods, which as you can see from the following code snippets is extremely easy. First the GetTrainerList method:

Private Sub GetTrainerList() Set adcTrainerList.Recordset = objFacade.GetTrainerList() End Sub

Now the GetCountryList method:

Private Sub GetCountryList() Set adcCountries.Recordset = objFacade.GetCountryList() End Sub

And that's it! You can now consider your facade object good enough to deliver to the GUI developers. They can make good use of it. Perhaps they will even suggest some early improvements.

The Save, Delete, and GetEmpty methods deferred

Of course, you should also include mechanisms in your test form to test the Save, Delete, and GetEmpty methods. We won't, however, bother with that now. Instead we'll see what the GUI developers can do with the facade class we give them. We'll do that in the next chapter.

Before we go on to do that, let's just briefly mention XML in connection with these early prototypes.

What About XML?

This chapter assumes that you're using ADO recordsets rather than XML documents to transport your data. If you used XML, the main difference from the procedures we followed in this chapter would be that functions now returning ADO recordsets would return string variables containing XML text. Also, method call arguments now specifying ADO recordsets would change into such string variables.

We talk specifically about XML in Chapters 20 and 21, but you should understand that nearly all the text and graphics of this chapter will remain valid for you even if you're going to use XML.



Designing for scalability with Microsoft Windows DNA
Designing for Scalability with Microsoft Windows DNA (DV-MPS Designing)
ISBN: 0735609683
EAN: 2147483647
Year: 2000
Pages: 133

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