Chapter 6:
![]()
Chapter 6 |
Chapter 5 expanded the notion of collections to include maps. Important topics discussed were information hiding and documentation. Static variables and constants were also examined. Chapter 6 does not introduce new Java syntax but important ideas about programming: testing small units, automating test, regression testing, manual testing and debugging.
Exercise 1 - diary-prototype project In BlueJ
- Open project chapter06\diary-prototype
- Select Day class.
- Click Tools.
- Project Documentation.
- What are the stated values of the dayNumber parameter to the Day constructor?
- Would you expect it to work for those values?
- What about other values?
- Construct a Day object.
- Are you testing a unit or the complete diary application?
- Construct another Day object using dayNumber 367.
- 367 exceeds the stated Day constructor boundary condition. Did the constructor fail?
- Do you think something will eventually fail later?
- Is it better to fail if the stated operating conditions are violated or try to give some response?
- What is another boundary condition?
Exercise 1.5 - Inspectors In BlueJ
- Construct a Day object.
- Inspect the Day object to determine if enough space is available for storing hourly appointments that start at 9am and run until 6pm?
- Construct three Appointment objects of 1 hour duration.
- Make appointments for 9am, 1pm and 5pm.
- Inspect the Day object to verify that the appointments occupy the correct positions.
- What is the Day class makeAppointment method boundary condition? Test it.
- Test whether two appointments can be scheduled at the same time.
- Have you just performed unit or application testing?
| positive testing - Testing cases that are expected to succeed. |
| negative testing - Testing cases that are expected to fail. |
Exercise 2 - Positive and negative testing In BlueJ
- Construct one Appointment object of 10 hour duration and construct a Day object.
- Make an appointment starting at 9am.
- What did your test indicate?
- Did the makeAppointment method work as specified?
- What were the makeAppointment method specifications?
- Have you just performed positive or negative testing?
- Can you think of another, similar test for the makeAppointment method?
| test automation - Test using a program (testing harness) rather than manually. Favored because repeatable, easier and more reliable than manual testing or inspection. |
| regression testing - Because corrections or other changes can introduce errors, earlier tests must be performed again. |
The following class automates tests for Exercise 3.
public class Exercise3Tests
{
public Exercise3Tests()
{ }
public void test()
{
Day day4 = new Day( 4 );
Appointment appt10 = new Appointment("Sleep all day", 10);
day4.makeAppointment( 9, appt10 );
}
}
Exercise 3 - Test automation ![]()
In BlueJay
- Create a new class Exercise3Tests in the diary-prototype project.
- Copy and paste the above class.
- The class diagram should appear as at right.
- Create an Exercise3Tests object.
- Call method test().
- Did the automated test produce the same results as the manual tests?
- Is this a good test to automate?
- Change the test() method to:
- Construct a Day object.
- Construct three Appointment objects of 1 hour duration.
- Make appointments for 9am, 1pm and 5pm.
- Test that appointments are placed at the correct times using the Day class showAppointments() method.
- Test whether two appointments can be scheduled at the same time.
Exercise 5 - Automation of tests In BlueJ
- Change the test() method of Exercise 3 to return a boolean type.
- The result returned should be the conjunction (&&) of the appointments for 9am, 1pm and 5pm.
- Note that makeAppointment returns false if the appointment is not made.
- Combine the results of the three makeAppointment calls using &&.
- Call your test() method.
- Change one of the appointments to 6pm and call your test() method again.
- Is this a positive or negative test?
- In this case all positive tests return true to correctly indicate success. Results can be combined using and (&&). All negative tests return false to correctly indicate failure. How would we combine test results to indicate the failure of a set of negative tests?
- Can all method tests easily be performed automatically?
- If not, give an example of a method signature that cannot be easily tested directly.
| interface - The point of connection between two modules, generally through methods. |
A calculator can be divided into two parts:
- user interface for the buttons and display
- calculation engine for the computation
The interface to a simplified calculation engine consists of methods with the signatures of:
- public void plus();
- public void minus();
- public void equals();
- public void clear();
- public int getDisplayValue();
- public void numberPressed(int number);
Because the calculation engine is separate from the the user interface, it can be implemented and fully tested independently of the user interface.
Exercise 5 - Modularization and interfaces In BlueJ
- Open project chapter06\calculator-engine
- Create a CalcEngineTester object.
- Call the testAll() method.
- Do you trust the printed results?
- Call the testAll() method again.
- Do you now trust the printed results?
- The method at right tests the plus() method.
- Change to test 32 + 4 =
- engine is a CalcEngine field of CalcEngineTester.
- Call the testPlus() method at least twice.
- Do you trust the results?
public int testPlus()
{
// Make sure the engine is in a valid starting state.
engine.clear();
// Simulate the presses: 3 + 4 =
engine.numberPressed(3);
engine.plus();
engine.numberPressed(4);
engine.equals();
// Return the result, which should be 7.
return engine.getDisplayValue();
}
Exercise 6 - Modularization and interfaces In BlueJ
- The method at right tests the minus() method.
- Change to test 32 - 4 =
- Call the testMinus() method at least twice.
- Do you trust the results of minus()?
public int testMinus()
{
// Make sure the engine is in a valid starting state.
engine.clear();
// Simulate the presses: 9 - 4 =
engine.numberPressed(9);
engine.minus();
engine.numberPressed(4);
engine.equals();
// Return the result, which should be 5.
return engine.getDisplayValue();
}
Exercise 7 - Commenting and style In BlueJ
- Open CalcEngine class.
- Do the comments seem sufficient to explain the class and method use?
- Is the source code layout reasonably consistent to the eye?
- Indentation.
- Use of { and }.
- Commenting consistent.
- Click the Implementation button and change to Interface to display the class documentation from the comments.
- Is the documentation sufficient to use the CalcEngine class without reading the source code?
Public manual walkthroughs share program analysis with others. Though time consuming, it is an important tool for analyzing code that fails for undetermined reasons or for code that cannot be live tested (e.g. controlling an emergency in a nuclear reactor).
Essentially the code in question is discussed and hand executed. You may have already done this with others on homework assignments then you know that it helps.
Exercise 8 - Manual walkthroughs to find errors In BlueJ
- Create a CalcEngineTester object.
- Call the testMinus() method at least twice. Note that the results differ between the first and second calls.
- Knowing that the first call works correctly with input of:
- 9 - 4 =
Let's assume that we've determined that after the first call the CalcEngine object has the following state:
- previousOperator = '-'
leftOperand = 0
displayValue = 5The second call fails with input of:
- 9 - 4 =
When minus() is called the second time the input so far to cause minus() to be called has been: 9 -.
The state is now:
- previousOperator = '-'
leftOperand = 0
displayValue = 9All appears well. Now to start our manual walkthrough of the CalcEngine class:
- Line 3 calls applyPreviousOperator() and previousOperator = '-'.
- Because previousOperator = '-' line 20 is executed and performs:
- leftOperand -= displayValue
which is:
- leftOperand = leftOperand - displayValue or 0 - 9 = -9
- When the number 4 and '=' is entered, the equals() method at line 7 is called. The object state is:
- previousOperator = '-'
leftOperand = -9
displayValue = 4
and the statement executed is line 12:
displayValue = leftOperand - displayValue or -9 - 4 = -13
- We found the problem.
- leftOperand = -9
when it should be:
- leftOperand = 9
Retracing our steps (something a debugger normally doesn't do) we may notice applyPreviousOperator() with previousOperator = '-' is the trouble point, in line 20. In fact line 22 should have been executed instead:
- leftOperand = displayValue = 9
- We may realize that the real problem is that after the '=' was entered in 9 - 4 =, previousOperator = ' ' rather than previousOperator = '-'.
Adding the following after line 13 solves the problem:
previousOperator = ' '
- public void minus()
- {
- applyPreviousOperator();
- previousOperator = '-';
- displayValue = 0;
- }
- public void equals()
- {
- if(previousOperator == '+')
- displayValue = leftOperand + displayValue;
- else
- displayValue = leftOperand - displayValue;
- leftOperand = 0;
- }
- private void applyPreviousOperator()
- {
- if(previousOperator == '+')
- leftOperand += displayValue;
- else if(previousOperator == '-')
- leftOperand -= displayValue;
- else
- leftOperand = displayValue;
- }
Printing the state of an object (fields), parameters and local variables as a program executes has several advantages over debugging and walkthroughs.
The following includes printing of all fields on entry and exit of the minus() method. The results of calling testMinus() twice is listed below.
- public class CalcEngine
- {
- private int displayValue;
- private char previousOperator;
- private int leftOperand;
- public void minus()
- {
- printState( "minus() entry");
- applyPreviousOperator();
- previousOperator = '-';
- displayValue = 0;
- printState( "minus() exit" );
- }
- private void printState( String where )
- {
- System.out.println(where+": previousOperator="+previousOperator+
- " displayValue="+displayValue+" leftOperand="+leftOperand);
- }
- }
minus() entry: previousOperator= displayValue=9 leftOperand=0
minus() exit: previousOperator=- displayValue=0 leftOperand=9
minus() entry: previousOperator=- displayValue=9 leftOperand=0
minus() exit: previousOperator=- displayValue=0 leftOperand=-9
Software development ideally is a cycle of:
- Analysis to determine an appropriate solution
- Designing a solution
- Coding the solution
- Testing to verify correctness
- Use of production system
- Maintenance by modifying, correcting, improving.
Testing and maintenance both benefit from printing debugging information while the program is running. In the production system, such debugging information should be turned off. Because most successful systems move often between testing, production and maintenance, debugging should be easily turned on and off.
The following uses the value of the field debugging=true to turn printing On. Change debugging=false to turn printing Off.
- public class CalcEngine
- {
- private int displayValue;
- private char previousOperator;
- private int leftOperand;
- private boolean debugging = true;
- public void minus()
- {
- printState( "minus() entry");
- applyPreviousOperator();
- previousOperator = '-';
- displayValue = 0;
- printState( "minus() exit" );
- }
- private void printState( String where )
- {
- if ( debugging )
- System.out.println(where+": previousOperator="+previousOperator+
- " displayValue="+displayValue+" leftOperand="+leftOperand);
- }
- }
Please send any comments to: jfdoyle@ius.edu
Copyright ©
2001-2004 by cgranda@ius.edu . All
rights reserved.