Testing and Debugging Windows Services and Web Services in .NET FrameworkThis article describes the testing and debugging windows services in .Net
|
|
|
| 2.4/5.0 (5 votes total) |
|
|
|
Team uCertify September 12, 2006
|
Team uCertify |
uCertify was formed in 1996 with an aim to offer high quality
educational training software and services in the field of information
technology to its customers. uCertify provides exam preparation
solutions for the certification exams of Microsoft, CIW, CompTIA,
Oracle, Sun and other leading IT vendors. To know more about uCertify,
please visit http://www.ucertify.com/ |
Team uCertify
has written 8 articles for WebKnowHow. |
View all articles by Team uCertify... |
Various tracing techniques have also been implemented to trace
errors or defects in the program code and debug them so that the cause
of errors can be easily detected and the application can be defect free.
When
an application is developed, it is required to ensure that the
application is free from defects and it fulfills the requirements for
which it has been developed. Therefore, developers perform various
levels of testing on an application. Testing also measures the quality
of an application. It reduces the cost of developing an application by
eliminating the cost of rectifying errors after the application has
been deployed. So, the process of testing is an important phase in the
software development life cycle. An application can be subjected to the
following levels of testing:
- Requirements Testing:
Requirements testing is performed before any other levels of testing.
In the process of Requirements testing, it is verified whether or not
the application fulfills all the requirements as specified in the
software specification.
- Usability Testing:
Usability testing is performed on the application to test whether the
user is able to use the application without any problems. During the
process of Usability testing, various checks are performed to verify
that the application meets the requirements.
- Unit Testing:
Unit testing is the lowest level of testing. At this level, each
elementary unit of the application is tested separately before
integrating it into modules. Unit testing requires basic tests at the
component level to determine whether it behaves exactly as it was
expected. This testing requires small, special programs known as test
drivers and stubs to be written. These programs use the component or
the class being tested and are used throughout the testing process. The
following are some of the advantages of Unit testing:
- Unit
testing is cost effective, as the test drivers and stubs can be reused
during the testing process, and the cost of retesting can be controlled
in a much better way.
- It enhances the process of testing, as each elementary unit of the application is tested separately.
- It
has been proven that during the process of Unit testing a large
percentage of defects are identified and can be removed at the initial
level.
- It also simplifies the process of debugging, as it
limits the search for errors to a small unit of the application instead
of having to find out errors in the whole of the application.
- Integration Testing:
Integration testing is the integration or combination of two or more
units (already being tested) into one component. It also tests the
interfaces between those units. In this level of testing, each
component is tested before being integrated into a module, and each of
the modules is tested before being integrated into an application.
Integration testing identifies those errors that can occur while
combining two or more elementary units of the application. Integration
testing can be performed in a variety of ways, but the following are
the three common approaches that are adopted during this level of
testing:
- Top-down approach:
The top-down approach to Integration testing starts with the high-level
modules that are integrated first, and then it gradually proceeds
toward the low-level subsystems. In this approach, high-level logic and
data flow are tested before writing stubs for the utility modules in
the development process. But the stubs complicate the testing process,
as the low-level utilities are tested much later in the development
cycle.
- Bottom-up approach:
The bottom-up approach to Integration testing starts with the low-level
units that are integrated first, and then it gradually proceeds toward
the high-level subsystems. In this approach, smaller units or utility
modules are tested much earlier than the high-level logic and data flow
in the development process. This approach requires writing test
drivers, instead of stubs, for testing the integration between the
subsystems. But the test drivers also create complications in the
testing process. Like the top-down approach, this approach, too, has a
weak support for early release of limited functionality.
- Umbrella approach:
The umbrella approach to Integration testing combines the two
approaches that are the top-down approach and the bottom-up approach.
This approach focuses mainly upon testing the modules that contain high
degree of user interaction. In this approach, the input modules are
integrated in the bottom-up pattern, and the output modules are
integrated in the top-down manner. This approach is beneficial in the
sense that it enables early release of a GUI-based application that
enhances its functionality. But this approach is less systematic than
the other two approaches.
- Regression Testing:
Regression testing can be performed any time when a program needs to be
modified either to add a feature or to fix an error. It is the process
of repeating Unit testing and Integration testing along with the new
tests. It ensures that no existing errors have reappeared and no new
errors are introduced.
Implementing Tracing and Debugging
Tracing
is the process of recording information about program execution. The
execution of a program can easily be traced by generating messages
about code execution while it is running. Tracing is an important part
in the process of testing. It tracks events in each line of program
code and reveals the presence of errors in the application. On the
other hand, debugging is the process of finding and correcting the
logic errors that were found during the tracing process. Hence,
debugging is significant in the testing process in the sense that it
debugs and troubleshoots the application and determines that the
application is defect free and should execute properly.
While
developing an application, tracing and debugging instrumentation can be
added to the .NET application by using the Trace and Debug classes
derived from the System.Diagnostics namespace. Placing trace statements
at various strategic locations in the program code can instrument a
distributed application. By using the Trace and Debug classes,
developers can obtain useful information whenever the program gives
erroneous results and monitor the performance of the application.
Therefore, tracing and debugging help the developer to closely examine
how well the program code is executing and how well the application
fulfills the requirements defined in the software specification.
Various
methods and properties of the Trace and Debug classes can be useful
when they are placed within the program in order to track errors in the
code at runtime, and to debug and monitor the efficiency of the
application. The following are the methods and properties of the Trace
and Debug classes:
Member Name
| Type
| Description
| Assert()
| Method
| Checks for a particular condition and evaluates to true at runtime. It displays a message if the condition is false.
| Close()
| Method
| Flushes the output buffer and then closes the connection with the Listeners collection.
| Fail()
| Method
| Exhibits an error message.
| Flush()
| Method
| Writes all the buffered data to the Listeners collection and then flushes the output buffer.
| Indent()
| Method
| Increments the current IndentLevel property by one.
| Unindent()
| Method
| Decrements the current IndentLevel property by one.
| Write()
| Method
| Writes information to the trace listeners in the Listeners collection.
| WriteIf()
| Method
| Writes information to the trace listeners only if the condition is true.
| WriteLine()
| Method
| Writes appended information with a new line character to the trace listeners in the Listeners collection.
| WriteLineIf()
| Method
| Writes
appended information with a new line character to the trace listeners
in the Listeners collection if the condition is true.
| AutoFlush
| Property
| Sets the value to true indicating whether the Flush method should be called on Listeners after every write.
| IndentLevel
| Property
| Identifies the indent level. Its default property value is zero.
| IndentSize
| Property
| Specifies the number of spaces in an indent. Its default indent size is four.
| Listeners
| Property
| Specifies the collections of listeners that monitor the debug output.
|
The following code snippets written in Visual Basic .NET show how to use various methods of the Trace and Debug classes:
' Write a debug assertion Debug.Assert(Num1 <= 0, "value entered is invalid", "positive value in debug mode") ' Write a trace assertion Trace.Assert(Num1 <= 0, "value entered is invalid", "positive value in trace mode")
' Write a debug message Dim Num1 As Integer For Num1=1 To 10 Step 1 Num1=Num1+2 Debug.WriteLine(Num1, "Value of Num1 is") ' Write a debug message if the condition is true Debug.WriteLineIf(Num1>10, "Value should not be greater than 10") Next
' Write a failure message Try Trace.Fail("Do not display the message") End Try
' Use of WriteLine method of the Debug class Debug.WriteLine("Choose the following list of errors:") ' Use of Indent method of the Debug class Debug.Indent() Debug.WriteLine("Error No 1: File1 not found") Debug.WriteLine("Error No 2: Directory not found") ' Use of Unindent method of the Debug class Debug.Unindent() Debug.WriteLine("List of errors ends here") ' Flush and close the output stream. Debug.Flush() Debug.Close()
The following code snippets written in Visual C# .NET show how to use various methods of the Trace and Debug classes:
//Write a debug assertion Debug.Assert(Num1 <= 0, "value entered is invalid", "positive value in debug mode"); // Write a trace assertion Trace.Assert(Num1 <= 0, "value entered is invalid", "positive value in trace mode");
// Write a debug message int Num1; for (Num1=1; Num1<=10; Num1++) { Num1=Num1+2; Debug.WriteLine(Num1, "Value of Num1 is"); // Write a debug message if the condition is true Debug.WriteLineIf(Num1>10, "Value should not be greater than 10"); }
// Write a failure message try { Trace.Fail("Do not display the message "); }
// Use of WriteLine method of the Debug class Debug.WriteLine("Choose the following list of errors:"); // Use of Indent method of the Debug class Debug.Indent(); Debug.WriteLine("Error No 1: File1 not found"); Debug.WriteLine("Error No 2: Directory not found"); // Use of Unindent method of the Debug class Debug.Unindent(); Debug.WriteLine("List of errors ends here"); // Flush and close the output stream. Debug.Flush(); Debug.Close();
Trace Listeners
Trace
listeners are classes responsible for collecting, storing, and routing
tracing messages generated by the Trace and Debug classes. The tracing
outputs are then directed to an appropriate destination such as a
window, a log, or a text file. Multiple listeners can be associated
with the Trace and Debug classes by adding the objects of a listener
class to their Listeners property. The TraceListener class that is
derived from the System.Diagnostics namespace has three predefined
objects. They are as follows:
- DefaultTraceListener:
DefaultTraceListener, which is an object of the TraceListener class, is
automatically included in the Listeners collection. Its default
function is to output debugging or tracing messages, such as Write and
WriteLine messages, to the OutputDebugString and the Debugger.Log
methods that appear in the output window. The following code snippet
written in Visual Basic .NET displays the output debugging or tracing
messages:
' Sends output messages to the Listeners collection. ' Write an output message when debugging Debug.WriteLine("Error in line no. 36 of File1.txt") ' Write an output message when tracing Trace.WriteLine("Error in line no. 36 of File1.txt")
The following code snippet written in Visual C# .NET displays the output debugging or tracing messages:
/*Sends output messages to the Listeners collection. Write an output message when debugging*/ Debug.WriteLine("Error in line no. 36 of File1.txt"); //Write an output message when tracing Trace.WriteLine("Error in line no. 36 of File1.txt");
- TextWriterTraceListener:
TextWriterTraceListener is an object of the TraceListener class. It
writes messages to an object of the Stream class or to an object of the
TextWriter class. The messages can also be written to a console or to
an output file. The following code snippet written in Visual Basic .NET
writes text to an output file or stream named File1.txt:
Public Shared Sub Main() ' Creates an output file. Dim MyOutputFile As Stream = File.Create("File1.txt") Dim TextListener1 As New TextWriterTraceListener(MyOutputFile) Trace.Listeners.Add(TextListener1) ' Writes a text writer to the console screen add to the trace listeners. Dim Writer1 As New TextWriterTraceListener(System.Console.Out) Trace.Listeners.Add(Writer1) ' Writes output message to the output file and to a console screen. Trace.Write("This file is a test file.") ' Flush and close the output file. Trace.Flush() Writer1.Flush() Writer1.Close() End Sub
The following code snippet written in Visual C# .NET writes text to an output file or stream named File1.txt:
public static void Main() { // Creates an output file. Stream MyOutputFile = File.Create("File1.txt"); TextWriterTraceListener TextListener1 = new TextWriterTraceListener(MyOutputFile); Trace.Listeners.Add(TextListener1); // Writes a text writer to the console screen add to the trace listeners. TextWriterTraceListener Writer1 = new TextWriterTraceListener(System.Console.Out); Trace.Listeners.Add(Writer1); // Writes output message to the output file and to a console screen. Trace.Write("This file is a test file."); // Flush and close the output file. Trace.Flush(); Writer1.Flush(); Writer1.Close(); }
- EventLogTraceListener:
EventLogTraceListener is an object of the TraceListener class. It
redirects its tracing or debugging output messages to a Windows event
log. The following code snippet written in Visual Basic .NET redirects
the output message to the Windows event log:
' Creates a trace listener for the event log. Dim TraceListener1 As New EventLogTraceListener("MyOwnEventLog") ' Adds the event log trace listener to the Listeners collection. Trace.Listeners.Add(TraceListener1) ' Writes output message to the event log. Trace.WriteLine("Output test file")
The following code snippet written in Visual C# .NET redirects the output message to the Windows event log:
// Creates a trace listener for the event log. EventLogTraceListener TraceListener1 = new EventLogTraceListener("MyOwnEventLog"); // Adds the event log trace listener to the Listeners collection. Trace.Listeners.Add(TraceListener1); // Writes output message to the event log. Trace.WriteLine("Output test file");
Trace Switches
The
Switch class is an abstract base class that is derived from the
System.Diagnostics namespace. The Switch class provided by the .NET
Framework creates new debugging and tracing switches. There are two
derived classes of the Switch class, that are the BooleanSwitch class
and the TraceSwitch class.
The BooleanSwitch class enables or
disables a switch that controls tracing or debugging outputs. The
Enabled property of the BooleanSwitch object determines whether a
switch is enabled or disabled. The property value is set to true if the
switch is enabled, and the property value is set to false if the switch
is disabled. Therefore, the BooleanSwitch object acts like the toggle
switch.
The TraceSwitch class provides five different tracing
levels. On the basis of these tracing levels, the specified trace
messages are displayed. If a trace switch is enabled for a particular
level, the trace messages for that level will appear; and if it is
disabled, the trace messages will not appear. The following table
describes the five different tracing levels:
Enumerated Value
| Integer Value
| Types of Tracing Messages
| Off
| 0
| No message
| Error
| 1
| Only error messages
| Warning
| 2
| Warning and error messages
| Info
| 3
| Informational, warning, and error messages
| Verbose
| 4
| Verbose, informational, warning, and error messages
|
The
configuration file system in the TraceSwitch class can be used to
manage the state of the switches that permit greater flexibility.
Various switches can be turned on and off and can change levels of
tracing without recompiling the user's application. A BooleanSwitch is
disabled by default, and a TraceSwitch is set by default to the
TraceLevel.Off tracing level. Trace switches can be created as well as
placed in any specific part of the user's code. A trace switch can be
used to filter out messages based on their importance. It also provides
various properties to test the level of the switch, which are as
follows:
- Attributes: The
Attributes property inherited from the Switch class specifies the
custom switch attributes defined in the application's configuration
file.
- Description: The
Description property inherited from the Switch class describes a trace
switch, and its default property value is an empty string ("").
- DisplayName:
The DisplayName property inherited from the Switch class uses a name to
identify the switch. Its default property value is an empty string
("").
- Level: The Level
property sets the trace level that determines the tracing or debugging
messages. In order to set the level of the TraceSwitch, the
configuration file can be edited to correspond to the name of the
user's application.
- TraceError:
The TraceError property value returns true if the Level property is set
to the enumerated value of Error, Warning, Info, or Verbose; otherwise
it returns false.
- TraceInfo:
The TraceInfo property value returns true if the Level property is set
to the enumerated value of Info or Verbose; otherwise it returns false.
- TraceVerbose:
The TraceVerbose property value returns true if the Level property is
set only to the enumerated value of Verbose; otherwise it returns false.
- TraceWarning:
The TraceWarning property value returns true if the Level property is
set to the enumerated value of Warning, Info, or Verbose; otherwise it
returns false.
Therefore, the level of a
TraceSwitch can be set through the application configuration file, and
then the configured TraceSwitch level is used in the application. In
order to configure a TraceSwitch, the user can edit the configuration
file that corresponds to the name of the application. In the
configuration file, a user can add or remove a switch, can set the
value of a switch, or can clear all the switches previously set by the
application.
Summary
- When
an application is developed, it is required to ensure that the
application is defect free and fulfills the requirements for which it
was developed. Therefore, developers perform various levels of testing
on an application. The levels of testing include Requirements testing,
Usability testing, Unit testing, Integration testing, and Regression
testing.
- Tracing is a process of recording information
about program execution. The execution of a program can easily be
traced by generating messages about code execution while it is running.
On the other hand, debugging is a process of finding and correcting the
logic errors that were found during the tracing process.
- While
developing an application, tracing and debugging instrumentation can be
added to the .NET application by using the Trace and Debug classes
derived from the System.Diagnostics namespace.
- Various
methods and properties of the Trace and Debug classes can be useful
when they are placed within the program in order to track errors in the
code at runtime, and to debug and monitor the efficiency of the
application.
- Trace listeners are classes responsible for
collecting, storing, and routing tracing messages generated by the
Trace and Debug classes. The TraceListener class that is derived from
the System.Diagnostics namespace has three predefined objects, namely
the DefaultTraceListener object, the TextWriterTraceListener object,
and the EventLogTraceListener object.
- There are two
derived classes of the Switch class, that are the BooleanSwitch class
and the TraceSwitch class. The BooleanSwitch class enables or disables
a switch that controls tracing or debugging outputs. The TraceSwitch
class of the Switch class provides five different tracing levels, and
on that basis specified trace messages are displayed.
- ASP.NET
tracing allows the user to view trace messages and diagnostic
information about a Web request with the page output from a separate
trace viewer utility called as Trace.axd. The user can also write
custom trace messages by using the System.Web.TraceContext class.
- Debugging
a serviced component depends on whether the serviced component
application is a Library or a Server application. If the serviced
component is a Library application, it runs within the client
application process. Whereas, if the serviced component is a Server
application, it runs in a separate process known as dllhost.exe.
- A
breakpoint is a marker in the code in order to signal a debugger to
pause the execution. During the pause state of execution, the user can
take time to analyze variables, data records, and other settings in the
program. There can be four types of breakpoints in a program, namely
the File breakpoint, the Data breakpoint, the Address breakpoint, and
the Function breakpoint.
- Various debugging tools offered
by the Visual studio .NET can be used to analyze the values of
variables, and the results of expressions used in the code, so that the
cause of errors can be identified during the debugging process.
- To
debug an XML Web service, a debugger is attached to the ASP.NET worker
process (aspnet_wp.exe) or the client application to which the Web
method is called. SOAP extensions of the XML Web services can also be
used for debugging.
|