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”);