Unit 1 · Basics of Computer Programming

1.4.2Errors and test cases

Types of errors

ErrorDescriptionExample
Syntax errorBreaks the language rules; the compiler rejects itMissing semicolon
Runtime errorThe program compiles but stops (crashes) while runningInteger division by zero; calling a method on null
Logic errorThe program runs but gives wrong resultsUsing < instead of <= in a loop condition
Write codeCompileRunCheck outputSyntax errorbreaks the language rulese.g.missing ;Runtime errorcrashes while runninge.g.divide by zeroLogic errorruns, but the answer is wronge.g.< instead of <=caught by the compilercaught only by testing
The three kinds of error and when each one shows up

Syntax errors

A syntax error breaks the grammar rules of the language, so the compiler cannot understand the code and refuses to build the program. The IDE usually underlines it in red before you even run anything.

Java
int total = 0
System.out.println("Total: " + total);

The compiler reports something like ';' expected on the first line. Other common syntax errors are misspelt keywords (Int instead of int), missing brackets, and using a variable that was never declared. Syntax errors are the easiest to fix, because the compiler tells you where they are.

Runtime errors

The code compiles, but something impossible happens while it runs, and the program stops with an exception:

Java
int count = 0;
int average = 100 / count;   // ArithmeticException: / by zero

String name = null;
int n = name.length();       // NullPointerException

Other examples are reading past the end of an array (ArrayIndexOutOfBoundsException) and typing letters when a number is expected (InputMismatchException). Runtime errors often depend on the input, so a program can run correctly a hundred times and then crash on unusual data. That is one reason why invalid data must be tested.

Logic errors

The program runs and finishes, but the answer is wrong. The computer cannot detect these, because the code is perfectly legal; it just does not do what you meant.

Java
double average = a + b + c / 3;   // wrong: only c is divided by 3
double average = (a + b + c) / 3; // correct

Logic errors are the hardest to find. You find them by testing with values whose correct answers you already know, by tracing (see 1.4.1) and by using the debugger (see 1.4.3).

Designing test cases

A test case has an input, an expected output and the actual result. Always include:

invalidinvalidFCBA0506575100boundary values: 49, 50, 64, 65, 74, 75normal: 30normal: 85-5101, "abc"
Test data for the grade program: normal values inside each band, boundary values on each edge, and invalid values outside 0 to 100
IDInput (marks)Type of dataExpectedActualPass?
T180NormalA
T258NormalC
T375BoundaryA
T474BoundaryB
T565BoundaryB
T664BoundaryC
T750BoundaryC
T849BoundaryF
T9-5InvalidInvalid (rejected)
T10101InvalidInvalid (rejected)
T11abcInvalidInvalid (rejected)

Testing and debugging are different

Testing finds out whether there is a problem: you run the program with chosen data and compare the actual results with the expected results. Debugging finds out where and why the problem happens, and fixes it. Testing comes first; when a test fails, you debug; and after every fix you run all the tests again, because a fix in one place can break something somewhere else.

How to choose good test data

You cannot test every possible input, so you choose a small set of values that are most likely to reveal mistakes:

Writing a test case

Write the expected output before you run the test. If you run the program first and then copy what it printed into the "Expected" column, the test proves nothing. A good test case is specific: not "enter some marks" but "enter 65, expect B".

Tip: keep your test table. When you change the program later, run the same tests again. This is called regression testing: it checks that the change did not break anything that used to work.

Remember

  • Syntax errors are found by the compiler, runtime errors by a crash, logic errors by a wrong answer.
  • Always test normal, boundary and invalid data.
  • Decide the expected output before running each test.

Use the lab below to run the test cases against a correct program and a program with a hidden logic error.

Levels of testing you will meet: unit testing (one method or class), integration testing (classes working together) and system testing (the whole program).