CMPT 125
Verification and Testing
Objectives
Write pre-conditions and post-conditions for functions
Write simple loop invariants for functions
Use assert statements to check invariants
Use assert statements to test methods
September 2004
John Edgar
2
Beans in a Can Game
September 2004
John Edgar
3
Rules
A can contains black and white beans Two players take it
in turns to remove two beans from the can
If the two beans are the same colour, put back a black bean
If the two beans are different colours put back a white bean
They continue until only one bean remains
The player who initially guesses the colour of the last
remaining beans wins the games (and the beans?)
What should you guess if there are 51 white beans and
51 black beans in the can at the start?
Is there a general rule that tells you what colour to
guess?
September 2004
John Edgar
4
Writing Algorithms
Writing code, testing it and debugging it are often time
consuming processes
What is testing for?
To determine if the solution implemented by the program is
correct or to find bugs?
It is useful to be able to reason about the correctness of
a solution to avoid coding an incorrect solution
The goal of a program is to end with the correct result
given that the inputs to the program were as expected
More formally, we want to demonstrate that a program will
always terminate with the post-condition satisfied, if the
program's pre-conditions hold
September 2004
John Edgar
5
Pre-Conditions
A pre-condition is an assertion about conditions at the
beginning of a method
An assertion is a statement about a condition
More generally: a declaration that is made emphatically (as if no
supporting evidence were necessary)
It is part of the "contract" implicit in a method
If the pre-conditions are not true then the method is not
guaranteed to produce the desired results
e.g. for binary search, there is a pre-condition that the array or
list being searched is sorted, it is not, there is not guarantee that
the correct result will be returned
Or, to put it another way, that the post-conditions will hold
September 2004
John Edgar
6
Post-Conditions
A post-condition is an assertion about conditions at the
end of a method
The post-conditions describe the state after the method has
been run
They therefore describe the desired output of a method
To prove that an algorithm is correct we need to prove
that, if the pre-conditions are correct, following the steps
of the algorithm will lead to the post-conditions
We should be able to show how the each step of an algorithm
leads to the post-conditions
We can use loop invariants to reason about the correctness of
loops
September 2004
John Edgar
7
Example: Binary Search
// PRE: arr is in ascending sorted order
// POST: return i such that arr[i] == x if x is
//
not in arr, returns -1
public int binary_search(int[] arr, int x)
If the array is sorted (i.e. if the pre-condition is true) then
The correct result is returned (i.e. the post-condition will
be true)
If the pre-condition is not true then binary search may
not return the correct result
September 2004
John Edgar
8
Testing Pre and Post-conditions
The pre-conditions and post-conditions act as
documentation for a method
They say exactly what a method will do (the post-condition),
and when it can successfully be called (the pre-condition)
When developing a program, broken pre-conditions are
important
It means that there is an error somewhere
It is helpful to find the error as close to the responsible code as
possible
Pre-conditions and post-conditions can be tested using
assertions
September 2004
John Edgar
9
Assertions
Java provides an assert statement that consist of the
keyword, a condition and an optional message string
If the condition is true the statement does nothing
If the condition is false then an exception is thrown, making the
program crash
Crashing a program in this way allows errors to be found
as soon as possible and as close as possible to where
they occurred
This aids in the testing of a program
The assert statements would be removed in the live version of
the program
September 2004
John Edgar
10
Assertion Example
//Assume that len has previously been given a value
double radius = (len - 1) / 2.0;
assert radius > 0 : "radius should be positive";
If radius becomes negative the following error results:
java.lang.AssertionError: radius should be positive
at examTest.main(examTest.java:28)
Exception in thread "main"
September 2004
John Edgar
11
Using Java Assertions
The assert keyword was an addition to Java 1.4 so you
have to make sure that your compiler recognizes it
In Eclipse go to Project, Properties
Select Java Compiler
Click on the Configure Workspace Settings… button and
Go to the Compliance and Classfiles tab. Make sure that 1.4 is
selected for all three JDK Compliance dropdown lists
In addition you have tell the virtual machine not to ignore
assertions (the default)
In Eclipse, go to the Run configuration, select the Arguments tab
and in the lower edit box titled VM Arguments type -ea
September 2004
John Edgar
12
Example: Binary Search
// PRE: arr is in ascending sorted order
// POST: return i such that arr[i] == x if x is
//
not in arr, returns -1
public int binary_search(int[] arr, int x){
assert is_sorted_asc(arr) : "PRE arr is asc";
// … code to implement binary search …
// … which will have returned if x is in arr
assert !contains(arr, x) : "POST: ";
Assume that the methods is_sorted_asc and
contains exist
contains can be implemented using linear search which is
much easier to write than binary search
Assertions are used to test code during development, and will
be removed before releasing the program
September 2004
John Edgar
13
Unit Testing
Test each (non-trivial) function or method in a module or
class
Each method's tests should be independent from other methods'
tests if possible
The goal is to isolate each part of the program and show
that it is correct
Given a set of test cases this makes it easier for programmers to
refactor code and test that the module still works correctly
Once a module is complete it allows programmers to focus on
integration testing with confidence that the individual modules
are sound
Unit testing is part of the Extreme Programming
methodology (although it predates it)
September 2004
John Edgar
14
Unit Testing with Assertions
Using print statements to test the output of methods can
be time consuming and is prone to error
The console output has to be checked to ensure that it matches
to the expected output of each test
It is easy for the tester to miss an error
Instead assertions can be used to automatically test
code
A series of tests should be written for each method, where each
test consists of some input and the expected output
An assertion can then be written for each test
There are unit testing tools, such as JUnit
September 2004
John Edgar
15
Testing Binary Search
public static void main(String[] args)
{
int[] nums = {1, 4, 45, 65, 66, 67, 67, 903};
assert binary_search(nums, 1000) == -1;
assert binary_search(nums, 0) == -1;
assert binary_search(nums, 3) == -1;
assert binary_search(nums, 50) == -1;
assert binary_search(nums, 1) == 0;
assert binary_search(nums, 903) == 7;
assert binary_search(nums, 66) == 4;
System.out.println("all tests passed");
}
September 2004
John Edgar
16
Testing Binary Search: Notes
Each assert statement performs one test
If the test passes, nothing happens
If the test fails, the assert throws an error which crashes the
program
If desired, the assert statements could also show messages to
indicate what each test was doing
No knowledge of the actual algorithm is required to write,
or perform, these tests
This is sometimes referred to as black box testing
The tests cover a variety of possibilities
Tests should always include the extreme cases, that is, items
near the start or the end of the array, as this is often where bugs
are found
September 2004
John Edgar
17
Loop Invariants
A loop invariant is a boolean expression that is true
Before the loop starts,
After each execution of the loop and
After the loop has finished
Usually this boolean expression includes variables used
in the loop
Note that many invariants can be tested, but only useful ones
should be chosen!
That is, useful in determining whether or not the post-conditions
will hold when the algorithm is terminated
September 2004
John Edgar
18
Binary Search Loop Invariants
The low index should always be less than or equal to the
high index
low <= high
The target (x) should not be in the array from the start of
the array to index low – 1 or from index high + 1 to the
end of the array
x is not in arr[0], arr[1], arr[low-1]
x is not in arr[high+1], arr[high+2], arr[arr.length-1]
high – low + 1 should always be smaller than it was on
the previous iteration
Thinking about these invariants can help in writing a
correct loop
September 2004
John Edgar
19
Complete Binary Search Algorithm
public int binary_search(int[] arr, int x){
int low = 0;
int high = arr.length - 1;
int mid = 0;
while (low <= high){
mid = (low + high) / 2;
if(x == arr[mid]){
return mid;
} else if(x > arr[mid]){
low = mid + 1;
} else { //x < arr[mid]
high = mid - 1;
}
} //while
return -1; //x not found
}
September 2004
John Edgar
20
Class Invariants
A class invariant is an invariant on the values of the
variables of an object
For example, consider a MatrixPoint object that represents a
pixel in TheMatrix, and has variables x and y that represent the x
and y coordinates of the pixel
The point must fall within the bounds of TheMatrix
If TheMatrix is w pixels wide and h pixels high the class
invariant for the MatrixPoint object would be:
0 <= x < w && 0 <= y < h
All constructors and mutators should respect class
invariants
That is, they should always make sure that class invariants are
true
September 2004
John Edgar
21
© Copyright 2025 Paperzz