Skip to content
UoL CS Notes

CASE - Testing & Debugging Tools

COMP285 Lectures

In-Circuit Emulator (ICE)

This does all the functions of a software debugger but at the machine instruction level.

  • ICE replaces the CPU in the target motherboard.
  • Very useful for embedded debugging:
    • Smartphones
    • DVD Players

ICE Features

  • Breakpoint before instruction execution.
  • Breakpoint on complex conditions:
    • Write particular data value to a memory location.
    • Write and read from I/O.
    • Hardware interrupts.

There are some differences to software debuggers:

  • Faster
    • Runs at full CPU speed.
  • Can break on a full range of hardware conditions at the CPU level.
    • Register access.

In-circuit debugger diagram. 1

ICE Tracing

There are two different types of trace that the ICE can do:

  • Instruction Trace:

    The ICE can record all the instructions executed up to the break-point.

    How we got there.

  • Jump Trace:

    The ICE can trace all flow of control instructions going to a certain point.

Logic Analyser

This tool probes an existing CPU to read the signals that are coming to and from the CPU. It has the following features:

  • Can take a snapshot of code execution and include it with a trace of the code.
  • Can Run the code at full speed.
  • Doesn’t require debug code added.
  • Can debug race conditions that are speed sensitive.
  • Can monitor hardware and software interaction.
  • Can decompile the code to the original if the source code is loaded into the target.

This is just an oscilloscope with many channels and features.

You can’t step through code using this method.

Kernel Mode Soft Debugging

This has the same functions as ICE but uses debug features of the CPU and driver loaded into the OS.

This can be used to debug device drivers.

Profiler

This tool calculates how much:

  • Time is used by different parts of your code.
  • Memory is used by different parts of code.

This can be useful for:

  • Optimising code for speed.
  • Optimising code for memory footprint.

Logger

This records all the activities of a program. It can have the following use cases:

  • Security Logging
  • Financial Logging
  • Debug Logging
    • Entry and exit to methods.

This has to be coded into the program with statements like so:

trace ('could not find login', Logger::DEBUG);

Testing Frameworks

These are an important part of test driven development.

We can use the following unit testing software:

  • Junit
  • PHP Unit

These both:

  • Allow for testing code and production of test reports.
  • Have interactions in many editors.

Stress Testing Tools

The following are some examples of stress testing tools:

  • Mysqlslap
    • Sends a heavy load to a MySQL server.
  • Website Load Testing Tools:
    • Many options such as:
      • LOIC Simple
      • Neoload
    • Can simulate complex transactions and not just random traffic.

Benefits of Stress Testing

  • Can help in optimising the performance of your software.
  • Can determine the maximum user load.
  • Can determine what happens when the system reaches heavy load.

Reverse Engineering

This is the process of taking binaries, or object code and converting it to source code.

This can be used to:

  • Determine how a product works.
  • Determing is code is infringing IPR.
  • Breaking into systems and copy protection.

In order to have niceties such as variable and function names, the program must have debugging symbols.

ORM Relational Management

This allows you to save objects directly to a database without having to write MySQL statements.

This has the following benefits:

  • Saves Programming Time
  • Reduces MySQL Errors
  • Improves Performance:
    • Code can include performance enhances such as sharding.
  • Allows validation of parameters such as database table names.

Example of ORM with Hibernate

You can represent a table like so:

public class Stock implements java.io.Serializable {
	private Integer stockId;
	private String stockCode;
	private String stockName;
	private StockDetail stockDetail;
	
	//constructor & getter and setter methods
}

This must implement serializable so that it can be stored in a backing store and sent over the network.

You can then write the data for the table in the following format:

<hibernate-mapping>
   <class name="com.mkyong.stock.Stock" table="stock" catalog="mkyongdb">
      <id name="stockId" type="java.lang.Integer">
         <column name="STOCK_ID" />
         <generator class="identity" />
      </id>
      <property name="stockCode" type="string">
         <column name="STOCK_CODE" length="10" not-null="true" unique="true" />
      </property>
      <property name="stockName" type="string">
         <column name="STOCK_NAME" length="20" not-null="true" unique="true" />
      </property>
      <one-to-one name="stockDetail" class="com.mkyong.stock.StockDetail" cascade="save-update" />
   </class>
</hibernate-mapping>

Bug Fixing with Case Support

Without CASE there are limited records and the visibility of the bug fixing process is low. We can use a method like the following to take advantage of CASE tools:

  1. Tester finds a bug and records it on a bug management tool and assigns the bug to a programmer.
  2. The bug management tool sends an email to the programmer.
  3. The programmer logs into the bug management tool and accepts/rejects the bug and adds comments.
  4. The programmer pulls the latest code from a source control system.
  5. The programmer fixes and test the bug using a debugger.
  6. The programmer commits the code with a useful comment that links to the bug ID.
  7. The team leader downloads the source code and makes a new build.