Home Categories ASP Tutorials Tutorial

Testing and Debugging Windows Services and Web Services in .NET Framework

This article describes the testing and debugging windows services in .Net

2.4/5.0 (5 votes total)
Rate:

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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:
  1. 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");


  2. 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();
    }
  3. 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:
  1. Attributes: The Attributes property inherited from the Switch class specifies the custom switch attributes defined in the application's configuration file.
  2. Description: The Description property inherited from the Switch class describes a trace switch, and its default property value is an empty string ("").
  3. DisplayName: The DisplayName property inherited from the Switch class uses a name to identify the switch. Its default property value is an empty string ("").
  4. 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.
  5. 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.
  6. 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.
  7. TraceVerbose: The TraceVerbose property value returns true if the Level property is set only to the enumerated value of Verbose; otherwise it returns false.
  8. 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.
 



Add commentAdd comment (Comments: 0)  

Advertisement

Partners

Related Resources

Other Resources