7
Testing and
Debugging
CERTIFICATION OBJECTIVES
7.01 Creating a Unit Test Plan
7.02 Implementing Tracing
7.03 Instrumenting and Debugging a
Windows Service, a Serviced
Component, a .NET Remoting
Object, and an XML Web Service
7.04 Using Interactive Debugging
7.05 Logging Test Results
✓
Two-Minute Drill
Q&A
Self Test
CertPrs8 / MCAD/MCSD XML Web Services and Server Components Development with Visual Basic .NET / Lind / 222653-6 /
Chapter 7
P:\010Comp\CertPrs8\653-6\ch07.vp
Wednesday, October 30, 2002 9:50:38 AM
Color profile: Generic CMYK printer profile
Composite Default screen
CertPrs8 / MCAD/MCSD XML Web Services and Server Components Development with Visual Basic .NET / Lind /
222653-6 / Chapter 7
I
n this chapter, you will learn about the testing process and specifically how unit testing fits
into the overall testing of the application. You will also look at what tracing is and how you
can make use of it, as well as how you implement your remote components and retrieve
that information.
Debugging and especially how you debug remote components interactively will
also be handled here. Another interesting area you will look at is how you can use
2
Chapter 7: Testing and Debugging
P:\010Comp\CertPrs8\653-6\ch07.vp
Wednesday, October 30, 2002 9:50:39 AM
Color profile: Generic CMYK printer profile
Composite Default screen
Creating a Test Plan on the Evolutionary Model
3
CertPrs8 / MCAD/MCSD XML Web Services and Server Components Development with Visual Basic .NET / Lind / 222653-6 /
Chapter 7
■
Replaces the traditional development and test planning process The
traditional process follows the waterfall model, where one task flows into the
next in an ordered manner as in the following list:
■
Analyze requirements
■
Create designs and specifications
■
Create the code
■
Test
■
Release
When you reach the testing phase in this model, the application is already finished,
and when problems are identified, there is a major issue: in order to make repairs, you
make changes, but those changes will modify the application, so you need to start
testing again. This cycle of testing and modifications on the finished application can be
never-ending. The development cost also increases enormously—there are estimates
that the cost can increase by 100 times when testing is delayed until the application is
222653-6 / Chapter 7
Expect questions that make you select between the waterfall model and the
evolution model. You can rest assured that the evolution model will be the
right answer.
The evolution model uses the iterative steps from object-oriented analysis and
design (OOAD) to continuously analyze the application and build fully tested
parts of that application before moving on to the next cycle, which starts with
analysis again.
The unit test becomes a central task in the development of the application. As
you move forward, you will have more and more fully tested units that can be
assembled into larger units that are then tested, and so on until the application is
finished.
Testing should be planned in a fashion similar to the main development effort.
Planning for testing should be requirements based, drawing the test design from the
requirements section of the software specification. Testing generally identifies defects
(bugs) that allow, create, or cause unexpected behaviors in terms of the requirements.
The requirements for the software must be written in such a way that they can be
directly translated into test documentation. For example, requirements should be
■
Binding The customer demanded them.
■
Testable If you can’t test the requirement, there is no way of proving
compliance.
■
Clear They must be unambiguous and interpretable in only one way.
Planning then proceeds by designing test cases that will validate each of the
requirements. The test plan will outline the entire process with the individual test cases
included. The development of a solid test plan is built on the systematic analysis of the
application to make sure that everything is tested without repetitions. The plan ensures
that testing procedures are known and do not depend on accidental or random testing.
The testing process usually requires that you write a test harness that is used to
communicate with the software unit. The terminology used to describe this scenario
is that you will write a driver to simulate the caller and possibly a stub to simulate a
called unit. The test harness becomes part of the applications code base and will be
used for validation through the lifetime of the application.
The cost in time that is involved in writing the test harness makes it tempting to
try to test larger units rather than identifying and testing the smallest possible unit.
The problem with testing larger units is that it increases the difficulty in identifying
where a problem is located. If you have two software units and you decide to test
them together as one unit, you may face the following list of questions, which gives
you an idea of the complexity of finding a bug:
■
Is the error caused by a defect in the first unit?
■
Is the error caused by a defect in the second unit?
■
Is the error caused by a defect in the test harness?
■
Is the error caused by a defect in both the first and second units?
■
Is the error caused by a defect in the interface between the two units?
The complexity introduced makes it very hard to find the source of the
defect—this is one compelling reason for implementing unit testing.
Always select the smallest possible unit for the test.
P:\010Comp\CertPrs8\653-6\ch07.vp
Wednesday, October 30, 2002 9:50:39 AM
Color profile: Generic CMYK printer profile
Composite Default screen
6
Chapter 7: Testing and Debugging
End Property
Public Function Celsius() As Integer
Return m_temperature
End Function
Public Function Fahrenheit() As Integer
Return m_temperature
End Function
End Class
7.
Next, write the test harness to test the Temperature class. The logic
behind the test is that you will test the Celsius() and Fahrenheit()
functions to ensure that the class returns the correct value. The test plan is to
use a value of 30 Celsius and verify that it is correctly returned. Create a new
source file in the Testing directory; name the file Harness.vb.
P:\010Comp\CertPrs8\653-6\ch07.vp
Wednesday, October 30, 2002 9:50:39 AM
Color profile: Generic CMYK printer profile
Composite Default screen
Creating a Test Plan on the Evolutionary Model
7
CertPrs8 / MCAD/MCSD XML Web Services and Server Components Development with Visual Basic .NET / Lind / 222653-6 /
Chapter 7
8.
Enter the following Visual Basic .NET code in the Harness.vb file:
Public Class Tester
Public Shared Sub Main()
Dim t As Temperature = New Temperature()
Static Thirty As Integer = 30
t.Temp = Thirty ' assign the property 30 Celsius
' Now test the behavior when the temperature is set to 30 C
As you can see, there is a problem, and if you look at the Temperature
class, you will find that the temperature is stored using the absolute Kelvin
scale, but there is no conversion in the Celsius() or Fahrenheit()
functions. The next step provides the solution to the Celsius() function
problem.
P:\010Comp\CertPrs8\653-6\ch07.vp
Wednesday, October 30, 2002 9:50:39 AM
Color profile: Generic CMYK printer profile
Composite Default screen
8
Chapter 7: Testing and Debugging
CertPrs8 / MCAD/MCSD XML Web Services and Server Components Development with Visual Basic .NET / Lind /
222653-6 / Chapter 7
11.
Correct the Celsius() function to correctly convert from Kelvin to
Celsius. Here is the correct conversion:
Public Function Celsius() As Integer
Return m_temperature + 273 ' convert from Kelvin to Celsius
End Function
12.
Save and compile the harness program.
13.
Execute the harness program. This should be the result:
C:\VB\Testing>harness
The value is correct: 30 (Expected 30C)
The value is incorrect: -243 (Expected 86F)
14.
Correct the problem with the Fahrenheit() function using the
following code segment:
Public Function Fahrenheit() As Integer
9
CertPrs8 / MCAD/MCSD XML Web Services and Server Components Development with Visual Basic .NET / Lind / 222653-6 /
Chapter 7
has very poor support for early (proof of concept), limited-functionality releases
of the application.
■
The bottom-up strategy This strategy starts with the integration of the
lowest-level units first, with the result that the utility level of the application
is tested early in the process. This strategy minimizes the need for stubs while
demanding drivers; the high-level logic and data flow are not tested until the
later stages of the development cycle. The support for early releases is poor.
■
The umbrella strategy In this strategy, you test along the lines of
functional control and data-flow paths. The logic is to integrate low-level
functions first—as in the bottom-up strategy—after which the output from
each function is integrated in the top-down manner. This strategy minimizes
the need for stubs and drivers but also makes management of the testing
effort more complicated. The umbrella strategy leads to the possible early
release of limited-functionality proof-of-concept versions.
The integration testing is completed when the application is ready to be shipped
to the customer.
The most common model for testing is a combination of the umbrella model
and one of the other two models. That way, the early test versions can be
brought together with the users to validate the design as well as the
formalized top-down or bottom-up model. One word of advice, though:
ensure that management of the testing is tightly controlled.
Regression Testing
Regression testing refers to the retesting of units after the unit has been modified. You
perform the regression test by rerunning the original tests that were designed for that
unit. The testing will determine if the modification broke the unit or not. Regression
standard tests that are used whenever the program has to be tested. One of the tricky
aspects of the test library is to decide what to keep. Don’t spend too much time
analyzing the merits of a particular test case; if you can’t make up your mind, add it
to the library. The content of the library should be analyzed every so often to remove
duplicated test cases as well as invalid tests.
Software testing is as much a science as is software design, and the preceding
information is included as an overview of the topic. Remember that the exam will
assume that you know how to write a test harness for a unit.
Providing Test Data to Components and Applications
The selection of test data for use with the test cases is as important as the design of the
test cases themselves. The data that is used must be selected from the problem domain
of the development project. The data is usually identified during the analysis phase of
the project and should be verified with the domain experts of the project to ensure the
data is valid.
When developing components that quite possibly will be used in an international
environment, it is imperative that you provide for data that is valid for the different
locales of the users of the component. To that end, work with the domain experts to
identify the different locales that will be supported in the design and create data
definitions for each locale.
The most important aspect of the localized component is that the tests must
provide data in the format of the user locale and test that the component performs
the correct conversions. For example, if the locale of the user presents dates in the
YYYY.MM.DD format (2002.09.07), the test data must include that format to
ensure that the conversions work.
CERTIFICATION OBJECTIVE 7.02
Logging Test Results
The performance of tests is one part of testing—but there is an equally important part
that involves the logging or filing of the test data. The logging can be as low-tech as
P:\010Comp\CertPrs8\653-6\ch07.vp
Wednesday, October 30, 2002 9:50:40 AM
exercise and test the class.
I have found that the software class is a
manageable unit for testing, but that is based
on the assumption that the classes are built as
small single-use building blocks that will be
assembled into larger classes that in turn are
assembled into the application.
This brings us back to the proper class design
that is the basis of OOAD. With a proper class
design, the test cases will be easy to design and
the iterative nature of OOAD will lend itself to
providing a functional test plan.
FROM THE CLASSROOM
P:\010Comp\CertPrs8\653-6\ch07.vp
Wednesday, October 30, 2002 9:50:40 AM
Color profile: Generic CMYK printer profile
Composite Default screen
CERTIFICATION OBJECTIVE 7.03
Instrumenting and Debugging a Service
Instrumentation is the process of collecting information about a program while it is
running. A number of methods are available to us for collecting that information,
ranging from online debugging to using the performance counters that can be monitored
using operating system tools. The exam will test you on how to add trace statements and
performance counters, and how to debug a remote component using these techniques.
Two different classes are available to us for getting information from the running
application: the Trace class and the Debug class. These two classes are equivalent in
all but one respect—the Debug class will not be available if the application has been
compiled as a Release build, while the Trace class is available in both Debug and
Release builds. As the two classes are equivalent in all but this respect, you will
concentrate on the Trace class in this section. You will start with tracing to explore