Notes
Outline
Chapter 7
Programming by contract: preconditions and postconditions
This chapter discusses
An elaboration of precondition and postcondition.
Programming by contract.
Test plans.
Programming by contract
A programming style in which the invocation of a method is viewed as a contract between client and server, with each having explicitly stated responsibilities.
To imply a precondition, we will use the term ‘require:’.
To imply a postcondition, we will use the term ‘ensure:’.
The objective of programming by contract
Delineate, clearly and explicitly, responsibilities between client and server.
Delineate, clearly and explicitly, responsibilities between the user of a method and the implementor of the method.
Ensure that any possible run time error will be detected with minimal explicit error checking.
Unfortunately, Java requires all checking to be coded explicitly as part of the method implementation.
The objective of programming by contract (cont.)
Test for every possible error condition only once (for program efficiency).
Achieve a balance between program reliability and maintainability.
The contract
If the preconditions are satisfied, then the server guarantees that the postconditions will be satisfied when the method completes.
If the preconditions are not satisfied, that is, if the client does not meet his end of the contract, then the server promises nothing.
Explorer class
Constructor:
require:
hitStrength >= 0
stamina >= 0
ensure:
this.name() == name
this.location() == location
this.strength() == strength
this.stamina() == stamina
Explorer class (cont.)
Method takeHit:
require:
hitStrength >= 0
ensure:
this.stamina() <= old.stamina()
“old” refers to the value of the variable at the beginning of the method; it is not a Java construct.
What if preconditions are not met?
We could set the value to a default value if it doesn’t meet criteria.  But this isn’t entirely satisfactory, since it treats an error condition as a normal, expected, occurrence.
Usually an error is returned if the preconditions are not met.
CSCI.utilities package contains functionality for doing this.
Require class
Include the following statement immediately after the package statement.
import CSCI.utilities.*;
Now you can use the method condition in the Require class.
static public void condition
      (boolean precondition)
Require in Explorer method
public Explorer (String name,
     rooms.Room location,
     int hitStrength,
     int stamina) {
Require.condition(hitStrength >= 0);
Require.condition(stamina >= 0);
playerName = name;
room = location;
strengthPoints = hitStrength;
staminaPoints = stamina;
}
More on preconditions:
Occasionally, preconditions constrain the order in which methods can be invoked or require that an object be in a certain state before a given method can be invoked.
Example: an automobile must be running  before it can move.
More on postconditions:
Query postconditions:
Queries do not change objects’ states.
Query postconditions simply say something about the value returned.
Command postconditions:
Commands change states.
Command postconditions describe the new state after execution of the command.
Constructor postconditions:
describe the initial state of the object.
Part of the specification:
Since preconditions and postconditions are part of the specifications, they should not mention private implementation components.
The reset method.
ensure:
tally == 0  (This is not correct!)
Named constants
Use named constants rather than literals in preconditions and postconditions.
public int  suit ( )
ensure:
result == Card.CLUB ||
result == Card.DIAMOND ||
result == Card.HEART ||
result == Card.SPADE.
Creating a test plan
Test the implementation to insure that it conforms to the specifications.
Create a “test harness” to interact with the object.
The test system acts as the client of the object:
Invoke the object’s methods.
Examine the behavior of the object.
Testing stamina
Provide an initial value for the object’s stamina.
Invoke the takeHit method repeatedly.
After each invocation, query the object with the method stamina and report the result.
Testing stamina (cont.)
Sample test session:
Initial stamina value: 100
Stamina is now 100.
Strength of hit: 10
Stamina is now 90.
Strength of hit: 20
Stamina is now 70.
Stength of hit: 5
Stamina is now 65.
…
Creating a test plan
Develop a test plan, giving values to be tested, the purpose of the test and the individual test cases, and the expected results.
Test the system thoroughly, but not inordinately.  Explicitly include limiting values and “equivalence classes.”
If the system performs properly for one member of an “equivalence class,” it should perform properly for all members of the “equivalence class.”
Testing stamina
Purpose: test the stamina property of a Explorer object, as modified by the method takeHit.
Preconditions:
Initial value of stamina >=0
hitStrength argument to takeHit >=0
Postconditions:
stamina >=0
Testing stamina (cont.)
Test run 1:
Input
Initial stamina value:
100
hitStrength:
10
20
0
10
50
10
10
Testing stamina (cont.)
Test run 2:
Input
Initial stamina value:
50
hitStrength:
100
Test run 3:
Input
Initial stamina value
0
hitStrength
10
We’ve covered
Programming by contract.
The client satisfying the precondition.
The server satisfying the postcondition.
Test plans.
Glossary