cmpt125verification

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