Testing and Debugging Your Application

Lesson 1

Error Types

Syntax Errors

  • Compiler cannot process provided source code - e.g. keyword wrongly typed
  • Build project -> errors detected, underlined and added to task list
  • Double click error in task list - associated code highlighted
  • Obtain help by pressing F1
  • Minimal syntax checking provided whilst typing in code

Run Time

  • App performs illegal operation

    • Divide by zero
    • Security exceptions
  • Exception describing error is thrown - write code to handle it

Logical

  • Correct execution but unexpected results
  • e.g. calculate pay but multiply hours per week by 400, not 40

Break Mode

  • Halt program execution and step through line at a time
  • Enter on following conditions:
    • Choose to Step Into, Over or Out
    • Execution reaches breakpoint
    • Execution reaches stop statement
    • Unhandled exception thrown

Breakpoints

  • Function - stop at specified location in function

    • Click grey bar to left of code line to stop at
    • Right click on desired line and insert breakpoint
    • Insert via Debug menu
  • File - specified location in file
  • Address - when specified memory address accessed
  • Breakpoint window
    • manage all breakpoints
    • display information
    • create, delete or disable

Debugging Windows

  • Output - command line output, debug and trace statements
  • Locals (all vars), Autos (current and previous line vars), Watch (chosen vars) - monitor program variables
  • Command - execute procedures, evaluate expressions, change vars
    • Cannot accept data declarations
    • In Break mode
      • if enter statement / method call IDE switches to runtime, executes statement, return to break mode
      • print variable values - use ? operator

Lesson 2

Debug and Trace

  • Debug class - log messages during execution (of debug code)
  • Trace class - log messages during execution (both debug and release code)
  • Both classes contain static methods to test conditions and log data
  • Class output sent to listeners (and Output window)

Methods

  • Write - write to listeners unconditionally
  • WriteLine - write to listeners unconditionally followed by CR
  • WriteIf - write to listeners if Boolean expression true
  • WriteLineIf - write to listeners unconditionally followed by CR if Boolean expression true
  • Assert - displays message box and writes to listeners if Boolean expression false
  • Fail - displays message box and writes to listeners

Listeners Collection

  • Listeners collection organises and exposes classes that can receive trace output
  • Listeners collection initialised with DefaultTraceListener class - receives messageseven if no other listeners attached
  • DefaultTraceListener directs trace to IDE output window
  • 2 base trace classes
    • EventLogTraceListener - directs output to event log
    • TextWritertraceListener - directs output to stream or TextWriter
// Open (or create) file
System.IO.FileStream myLog = new System.IO.FileStream("C:\\myfile.txt", System.IO.FileMode.OpenOrCreate);

// Create TraceListener logging to specified file
TextWriterTraceListener myListener = new TextWriteTraceListener(myLog);

// Add to listeners collection
Trace.Listeners.Add(myListener);
  • To write to file must flush, either by explicitly calling trace method or setting AutoFlush property to true
  • Using EventLogTraceListener similar
    • Create new EventLog
    • Create EventLogTraceListener class
    • Add to listeners collection
// Create event log entitled "DebugLog"
EventLog myLog = new EventLog("Debug Log");

// Set EventLog source property (avoid error)
myLog.source = "Trace Output";

// Create EventLogTraceListener
EventLogTraceListener = new EventLogTraceListener(myLog);

Trace Switches

  • 2 types - BooleanSwitch class (on or off) and TraceSwitch class (five values)
  • Both classes require DisplayName (its name in configuration file) and Description
BooleanSwitch myBoolSwitch = newBooleanSwitch("Switch1", "Control Data Tracing");

TraceSwitch myTraceSwitch = new TraceSwitch("Switch2", "Control Form Tracing");
  • TraceSwitch = 5 settings, exposed by TraceSwitch.Level property

    • TraceLevel.Off
    • TraceLevel.Error
    • TraceLevel.Warning
    • TraceLevel.Info
    • TraceLevel.Verbose
  • TraceSwitch class exposed four Boolean properties corresponding to trace levels of same name, e.g. if TraceSwitch.Level = TraceLevel.Info then TraceSwitch.TraceInfo is true (as are TraceSwitch.TraceError and TraceSwitch.TraceWarning) while TraceSwitch.TraceVerbose is false
  • No auto hook-up between trace switches and statements, use TraceSwitch to test if output required:
Trace.WriteIf(myBoolSwitch.Enabled == true, "error");

Trace.WriteIf(myTraceSwitch.TraceInfo == true, "type mismatch");

Configure Trace Switches

  • Configured within XML application .config file
  • Config file located in executables folder
  • Config file called appname.exe.config
  • May need to create config file (not all apps have them)
  • When app creates trace switch it checks .config file for info on switch (identified by DisplayName)
  • To create file

  • Add new item from project menu
  • Choose text file and name appropriately
  • Type following
<?xml version="1.0" encoding="Windows-1252"?>
<configuration>
  < system.diagnostics>
    <switches>
      <add name="myBoolSwitch" value="0"/>
      <add name="myTraceSwitch" value="3"/>
    </switches>
  < /system.diagnostics>
</configuration>

Lesson 3

Unit Test Plan

  • Run-time and logical error snot detected without thorough testing
  • Testing and debugging separate but related activities

    • Debug = finding and correcting code errors
    • Testing = process by which errors found
  • Testing usually broken down by method, exercised using variety of params - termed unit testing
  • Cannot test all permutations - use representative examples (test cases)

Test Case Design

  • Minimum = exercise all lines of code
  • Design cases to work through all decision branches
  • App should behave as expected when normal params provided
  • App should degrade gracefully when parms outside bounds provided

    • Boundary conditions - minimum and maximum and off by one
    • Bad data - values well outside range (0, negative, etc.)
    • Data combinations - test all method parms at boundary, bad values, etc
  • Determine expected test case results prior to actual test
  • Compare obtained results with those expected

Lesson 4

Exceptions

  • Structured Exception Handling means of recovering gracefully from errors
  • Exception = instance of specialist class deriving from System.Exception

    • Message property = human readable description of error
    • StackTrace property = stack trace to pinpoint error location
  • Run time error occurs
    • Exception generated and passed up call stack to caller
    • If exception handler encountered it is handled, otherwise passed up stack to next method... and so on
    • If no handler found default used - message box displayed and app stopped

Exception Handler

  • Implemented on method basis - i.e. individually tailored to it and exceptions likely to be thrown
    • Wrap code associated with handler in try block
    • Add 1+ catch blocks to handle exceptions
    • Add code that must always be executed in finally block
public void Parse(string a string)
{
 try
 {
  double aDouble;
  aDouble = Double.Parse(aString);
 }

 catch (System.ArgumentNullException e)
 {
  // Code to handle null argument - e
  // contains ref to exception (access to 
  // its info)
 }

 catch
 { 
  // Catch any other exception
 }

 finally
 { 
  // Code that must be executed
 }
}
  • After code in (only one) catch block executed, the finally block is run
  • Write catch blocks in order from most to least specific
  • Can omit catch block (exception handled further up call stack) but still include finally block to execute any code in method that must run before return

Throwing Exceptions

  • 2 situations

    • Only partially handled exception and want to bubble it up call stack
    • Unacceptable condition occurred that cannot be handled locally and must be communicated to parent - throw standard or custom exception
  • Rethrow exception by using throw
try
{

}

catch (System.NullReferenceException e)
{
 // Assuming exception can not be handled 
 // rethrow

 throw e;
}
  • Can pass additional information on when rethrowing, e.g. to provide informative message around original exception
throw new NullReferenceException("Widget A is not set", e);
  • Custom exception - only for exceptional circumstances - not for use as communication between client and components (use events). Only use when conditions mean execution can not proceed without intervention
  • Custom exceptions derive from System.ApplicationException, e.g.
public class WidgetException:System.ApplicationException
{
 // Var to hold widget

 Widget mWidget;

 public Widget ErrorWidget
 {
  get
  {
   return mWidget; 
  }
 }

 // Constructor takes widget and string 

 //describing error conditions
 public WidgetException(Widget W, string S) : base(S)
 {
  mWidget = W;
 }
}

Widget Alpha;

throw new WidgetException(Alpha,"Alpha is corrupt");

Download