Introduction to Test-Driven Development
This lab is intended to familiarize you with the Test-Driven
Development process. It will walk through an example of developing a
program in a test-driven development style and then you will be asked
to do the same in an exercise.
Resources
1. What is Test-Driven Development (TDD)?
TDD develops tests and code in a unique order. TDD procedures work with
units of program functionality. Units are the smallest module of
functionality and are usually in the form of methods. TDD has six
distinct steps:
- Add a new test for an unimplemented unit of functionality.
- Run all previously written tests and see the newly added test fail.
- Write code that implements the new functionality.
- Run all tests and see them succeed.
- Refactor (rewrite to improve readability or structure).
- Start at the beginning (repeat).
As development continues, the programmer creates a suite of
unit tests that can be run automatically. As larger modules (entire
classes or packages, as opposed to single methods) are completed, more
tests may be added. The programmers now have a full regression test
suite to run whenever changes are made to the system. Changes can be
made with confidence, since if something breaks in another part of the
system, the regression tests are likely to catch it. Furthermore,
low-level design decisions are constantly being made as the programmer
develops tests and source code. By making constant decisions and
refactoring based on these decisions, a stable and well thought-out
architecture is produced. 2. TDD Example
Let's try out TDD! We want to develop an Alarm.java
class that will act like an alarm clock and hold the time that the
alarm should go off. We will want to set and retrieve the current
time the clock is set for. Step 1 of the TDD process is to add a test
for an unimplemented unit of functionality. We first want to create an
Alarm object to work with, so let's create a test to make sure our
object is created correctly (see below - bold indicates what we
are currently working on). Our Alarm needs to be able to hold an hour
and a minute on a 24-hour time scale. When clocks are first
plugged in, the alarm default is always 12:00AM. So in our test,
we create an Alarm object which should be initialized to 0 hours and 0
minutes on a 24-hour time scale (see line 10). Great, so we have
an idea for a constructor, now how are we going to test that it was
created correctly? We need a way to retrieve the two fields. Let's test
it using get() methods (lines 11-12). We will need two of
them - one for each field. Remember that we haven't written a single
line of source-code yet. By writing a test first, we are driving out
low-level design decisions which allows us to understand the conditions
in which our implementation should work.
Step 1 of implementing the Alarm() constructor functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 /* Test the Alarm constructor */
8 @Test
9 public void testAlarm() {
10 Alarm myAlarm = new Alarm();
11 assertEquals(0, myAlarm.getHour());
12 assertEquals(0, myAlarm.getMinute());
13 }
14 }
Step 2 now has us run
our test and watch it fail since the source-code is not implemented
yet. Well, we currently can't run our code since we have no code. Thus,
we must stub out the new methods so that we can compile and run our
code and watch our tests fail (see Alarm class). Changes below are
indicated in bold.
Step 2 of implementing the Alarm() constructor functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 /* Test the Alarm constructor */
8 @Test
9 public void testAlarm() {
10 Alarm myAlarm = new Alarm();
11 assertEquals(0, myAlarm.getHour());
12 assertEquals(0, myAlarm.getMinute());
13 }
14 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 /* Constructor to initialize our alarm */
4 public Alarm() {
5
6 }
7
8 /* Retrieve the hour */
9 public int getHour() {
10 return -1;
11 }
12
13 /* Retrieve the minute */
14 public int getMinute() {
15 return -1;
16 }
17 }
Now that we see our
tests fail since our get methods only return -1, we can move to step 3.
In this step we get to implement the new functionality. We need a way
to store the hour and minute. Let's create private instance variables
to hold these values (lines 3,4 of the Alarm class). Our constructor
can thus initialize these variables (lines 8,9 of the Alarm class).
Below are the changes to our code to implement these methods, noted in bold.
Step 3 of implementing the Alarm() constructor functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 /* Test the Alarm constructor */
8 @Test
9 public void testAlarm() {
10 Alarm myAlarm = new Alarm();
11 assertEquals(0, myAlarm.getHour());
12 assertEquals(0, myAlarm.getMinute());
13 }
14 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21 }
Step 4 now has us re-run the tests we wrote in step 1, and verify that
they all pass. In this case, our tests now pass since the get() method returns the expected value. Step 5 now has us refactor to improve any readability or structure. Our constructor and get()
methods are both fairly simple, so no refactoring is needed. Step 6
concludes an iteration of TDD and we can start over on a new unit of
functionality. Alright we did TDD! So why was developing code in that
manner so important? By writing our testAlarm() method before
implementing the actual constructor, we were forced to think about
conditions that the implementation should work under through specifying
expected outputs with given inputs. Furthermore, it drove out design
decisions - we needed a way to retrieve the values from our alarm, so
we created utility methods (get()).
Let's see another example of developing in a TDD fashion: setting the
alarm time. We need a way to give valid input. Starting with step
1, let's write a test to see how the set method should work (lines
15-37 of AlarmTest). We will need to specify proper time values on a
24-hour scale, so the method should let us know if it was successful in
setting the time. Let's have it return us a boolean to see if it
was successful. Code changes are indicated in bold.
Step 1 of implementing the setTime() functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 /* Test the Alarm constructor */
8 @Test
9 public void testAlarm() {
10 Alarm myAlarm = new Alarm();
11 assertEquals(0, myAlarm.getHour());
12 assertEquals(0, myAlarm.getMinute());
13 }
14
15 /* Test the setTime */
16 @Test
17 public void testSetTime() {
18 Alarm myAlarm = new Alarm();
19
20 // Try setting the time to 7:30AM
21 assertTrue(myAlarm.setTime(7,30));
22 assertEquals(7, myAlarm.getHour());
23 assertEquals(30, myAlarm.getMinute());
24
25 // Try setting the time to 5:53PM
26 assertTrue(myAlarm.setTime(17,53));
27 assertEquals(17, myAlarm.getHour());
28 assertEquals(53, myAlarm.getMinute());
29
30 // Try a few bad times!
31 assertFalse(myAlarm.setTime(-22,23));
32 assertFalse(myAlarm.setTime(4,87));
33
34 // Make sure the time did not change from the bad times
35 assertEquals(17, myAlarm.getHour());
36 assertEquals(53, myAlarm.getMinute());
37 }
38 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21 }
To move on to step 2, we must stub out the new methods so that we can
compile and run our code and watch our tests fail (lines 22-25 of
Alarm). Changes below are indicated in bold.
Step 2 of implementing the setTime() functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 /* Test the Alarm constructor */
8 @Test
9 public void testAlarm() {
10 Alarm myAlarm = new Alarm();
11 assertEquals(0, myAlarm.getHour());
12 assertEquals(0, myAlarm.getMinute());
13 }
14
15 /* Test the setTime */
16 @Test
17 public void testSetTime() {
18 Alarm myAlarm = new Alarm();
19
20 // Try setting the time to 7:30AM
21 assertTrue(myAlarm.setTime(7,30));
22 assertEquals(7, myAlarm.getHour());
23 assertEquals(30, myAlarm.getMinute());
24
25 // Try setting the time to 5:53PM
26 assertTrue(myAlarm.setTime(17,53));
27 assertEquals(17, myAlarm.getHour());
28 assertEquals(53, myAlarm.getMinute());
29
30 // Try a few bad times!
31 assertFalse(myAlarm.setTime(-22,23));
32 assertFalse(myAlarm.setTime(4,87));
33
34 // Make sure the time did not change from the bad times
35 assertEquals(17, myAlarm.getHour());
36 assertEquals(53, myAlarm.getMinute());
37 }
38 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21
22 /* Set the alarm time */
23 public boolean setTime(int hr, int min) {
24 return false;
25 }
26 }
Let's do step 3 of our process now. We want to implement the set time
functionality. This method needs to verify that the parameters are
legit time values and indicate if it was successful in setting the new
time. We first check to see that the hour is between 0 and 23,
and the minute is between 0 and 59, otherwise we are unsuccessful
(lines 24-26 of Alarm). If they are legit values, we set the new
time and return true for success (lines 27-31 of Alarm). Changes
are indicated in bold.
Step 3 of implementing the setTime() functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 /* Test the Alarm constructor */
8 @Test
9 public void testAlarm() {
10 Alarm myAlarm = new Alarm();
11 assertEquals(0, myAlarm.getHour());
12 assertEquals(0, myAlarm.getMinute());
13 }
14
15 /* Test the setTime */
16 @Test
17 public void testSetTime() {
18 Alarm myAlarm = new Alarm();
19
20 // Try setting the time to 7:30AM
21 assertTrue(myAlarm.setTime(7,30));
22 assertEquals(7, myAlarm.getHour());
23 assertEquals(30, myAlarm.getMinute());
24
25 // Try setting the time to 5:53PM
26 assertTrue(myAlarm.setTime(17,53));
27 assertEquals(17, myAlarm.getHour());
28 assertEquals(53, myAlarm.getMinute());
29
30 // Try a few bad times!
31 assertFalse(myAlarm.setTime(-22,23));
32 assertFalse(myAlarm.setTime(4,87));
33
34 // Make sure the time did not change from the bad times
35 assertEquals(17, myAlarm.getHour());
36 assertEquals(53, myAlarm.getMinute());
37 }
38 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21
22 /* Set the alarm time */
23 public boolean setTime(int hr, int min) {
24 if (hr > 23 || hr < 0 || min > 59 || min < 0) {
25 return false;
26 }
27 else {
28 hour = hr;
29 minute = min;
30 return true;
31 }
32 }
33 }
When we carry out step 4 of the TDD process, we verify that our tests
pass. Step 5 has us refactor to improve readability or structure.
Looking at our JUnit test code, we construct the same Alarm object to
use in the unit tests. This is a good candidate for belonging in a
@Before method. Let's add a setUp()
method (lines 9-13 of AlarmTest) and private variable (line 7 of
AlarmTest) to reuse our test object, instead of duplicating the code.
Changes below are in bold, and the constructor call is removed from testAlarm() and testSetTime().
Step 5 of implementing the setTime() functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 private Alarm myAlarm;
8
9 /* This '@Before' method is ran before every '@Test' method */
10 @Before
11 public void setUp() throws Exception {
12 myAlarm = new Alarm();
13 }
14
15 /* Test the Alarm constructor */
16 @Test
17 public void testAlarm() {
18 assertEquals(0, myAlarm.getHour());
19 assertEquals(0, myAlarm.getMinute());
20 }
21
22 /* Test the setTime */
23 @Test
24 public void testSetTime() {
25 // Try setting the time to 7:30AM
26 assertTrue(myAlarm.setTime(7,30));
27 assertEquals(7, myAlarm.getHour());
28 assertEquals(30, myAlarm.getMinute());
29
30 // Try setting the time to 5:53PM
31 assertTrue(myAlarm.setTime(17,53));
32 assertEquals(17, myAlarm.getHour());
33 assertEquals(53, myAlarm.getMinute());
34
35 // Try a few bad times!
36 assertFalse(myAlarm.setTime(-22,23));
37 assertFalse(myAlarm.setTime(4,87));
38
39 // Make sure the time did not change from the bad times
40 assertEquals(17, myAlarm.getHour());
41 assertEquals(53, myAlarm.getMinute());
42 }
43 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21
22 /* Set the alarm time */
23 public boolean setTime(int hr, int min) {
24 if (hr > 23 || hr < 0 || min > 59 || min < 0) {
25 return false;
26 }
27 else {
28 hour = hr;
29 minute = min;
30 return true;
31 }
32 }
33 }
Now we are ready to repeat with new functionality in step 6! Let's
see one last example of developing in a TDD fashion. We need
a way to display the time that is set for the alarm. A good
candidate for this is a toString() method. Starting
with step 1,
let's write a test (lines 44-60 of AlarmTest) to see how the set method
should work. It should be displayed in more typical 12-hour time with
an AM/PM indicator. Code changes are
indicated in bold.
Step 1 of implementing the toString() functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 private Alarm myAlarm;
8
9 /* This '@Before' method is ran before every '@Test' method */
10 @Before
11 public void setUp() throws Exception {
12 myAlarm = new Alarm();
13 }
14
15 /* Test the Alarm constructor */
16 @Test
17 public void testAlarm() {
18 assertEquals(0, myAlarm.getHour());
19 assertEquals(0, myAlarm.getMinute());
20 }
21
22 /* Test the setTime() method */
23 @Test
24 public void testSetTime() {
25 // Try setting the time to 7:30AM
26 assertTrue(myAlarm.setTime(7,30));
27 assertEquals(7, myAlarm.getHour());
28 assertEquals(30, myAlarm.getMinute());
29
30 // Try setting the time to 5:53PM
31 assertTrue(myAlarm.setTime(17,53));
32 assertEquals(17, myAlarm.getHour());
33 assertEquals(53, myAlarm.getMinute());
34
35 // Try a few bad times!
36 assertFalse(myAlarm.setTime(-22,23));
37 assertFalse(myAlarm.setTime(4,87));
38
39 // Make sure the time did not change from the bad times
40 assertEquals(17, myAlarm.getHour());
41 assertEquals(53, myAlarm.getMinute());
42 }
43
44 /* Test the toString() method */
45 @Test
46 public void toString() {
47 // Try 7:30AM
48 myAlarm.setTime(7,30);
49 assertEquals("7:30AM", myAlarm.toString());
50
51 // Try 5:53PM
52 myAlarm.setTime(17,53);
53 assertEquals("5:53PM", myAlarm.toString());
54
55 // Edge-cases 12:00AM and 12:00PM
56 myAlarm.setTime(0,0);
57 assertEquals("12:00AM", myAlarm.toString());
58 myAlarm.setTime(12,0);
59 assertEquals("12:00PM", myAlarm.toString());
60 }
61 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21
22 /* Set the alarm time */
23 public boolean setTime(int hr, int min) {
24 if (hr > 23 || hr < 0 || min > 59 || min < 0) {
25 return false;
26 }
27 else {
28 hour = hr;
29 minute = min;
30 return true;
31 }
32 }
33 }
To move on to step 2, we must stub out the new method so that we can
compile and run our code and watch our tests fail (lines 34-37 of Alarm). Changes below are
indicated in bold.
Step 2 of implementing the toString() functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 private Alarm myAlarm;
8
9 /* This '@Before' method is ran before every '@Test' method */
10 @Before
11 public void setUp() throws Exception {
12 myAlarm = new Alarm();
13 }
14
15 /* Test the Alarm constructor */
16 @Test
17 public void testAlarm() {
18 assertEquals(0, myAlarm.getHour());
19 assertEquals(0, myAlarm.getMinute());
20 }
21
22 /* Test the setTime() method */
23 @Test
24 public void testSetTime() {
25 // Try setting the time to 7:30AM
26 assertTrue(myAlarm.setTime(7,30));
27 assertEquals(7, myAlarm.getHour());
28 assertEquals(30, myAlarm.getMinute());
29
30 // Try setting the time to 5:53PM
31 assertTrue(myAlarm.setTime(17,53));
32 assertEquals(17, myAlarm.getHour());
33 assertEquals(53, myAlarm.getMinute());
34
35 // Try a few bad times!
36 assertFalse(myAlarm.setTime(-22,23));
37 assertFalse(myAlarm.setTime(4,87));
38
39 // Make sure the time did not change from the bad times
40 assertEquals(17, myAlarm.getHour());
41 assertEquals(53, myAlarm.getMinute());
42 }
43
44 /* Test the toString() method */
45 @Test
46 public void toString() {
47 // Try 7:30AM
48 myAlarm.setTime(7,30);
49 assertEquals("7:30AM", myAlarm.toString());
50
51 // Try 5:53PM
52 myAlarm.setTime(17,53);
53 assertEquals("5:53PM", myAlarm.toString());
54
55 // Edge-cases 12:00AM and 12:00PM
56 myAlarm.setTime(0,0);
57 assertEquals("12:00AM", myAlarm.toString());
58 myAlarm.setTime(12,0);
59 assertEquals("12:00PM", myAlarm.toString());
60 }
61 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21
22 /* Set the alarm time */
23 public boolean setTime(int hr, int min) {
24 if (hr > 23 || hr < 0 || min > 59 || min < 0) {
25 return false;
26 }
27 else {
28 hour = hr;
29 minute = min;
30 return true;
31 }
32 }
33
34 /* Display the time in String format */
35 public String toString() {
36 return "";
37 }
38 }
Let's do step 3 of our process now. We need to construct a string of
three parts for the implementation: the hour converted to 12-hour
scale, the minute, and an AM/PM indicator. Changes
are indicated in bold (lines 36-58 of Alarm).
Step 3 of implementing the toString() functionality.
1 import static org.junit.Assert.*;
2 import org.junit.Before;
3 import org.junit.Test;
4
5 public class AlarmTest {
6
7 private Alarm myAlarm;
8
9 /* This '@Before' method is ran before every '@Test' method */
10 @Before
11 public void setUp() throws Exception {
12 myAlarm = new Alarm();
13 }
14
15 /* Test the Alarm constructor */
16 @Test
17 public void testAlarm() {
18 assertEquals(0, myAlarm.getHour());
19 assertEquals(0, myAlarm.getMinute());
20 }
21
22 /* Test the setTime() method */
23 @Test
24 public void testSetTime() {
25 // Try setting the time to 7:30AM
26 assertTrue(myAlarm.setTime(7,30));
27 assertEquals(7, myAlarm.getHour());
28 assertEquals(30, myAlarm.getMinute());
29
30 // Try setting the time to 5:53PM
31 assertTrue(myAlarm.setTime(17,53));
32 assertEquals(17, myAlarm.getHour());
33 assertEquals(53, myAlarm.getMinute());
34
35 // Try a few bad times!
36 assertFalse(myAlarm.setTime(-22,23));
37 assertFalse(myAlarm.setTime(4,87));
38
39 // Make sure the time did not change from the bad times
40 assertEquals(17, myAlarm.getHour());
41 assertEquals(53, myAlarm.getMinute());
42 }
43
44 /* Test the toString() method */
45 @Test
46 public void toString() {
47 // Try 7:30AM
48 myAlarm.setTime(7,30);
49 assertEquals("7:30AM", myAlarm.toString());
50
51 // Try 5:53PM
52 myAlarm.setTime(17,53);
53 assertEquals("5:53PM", myAlarm.toString());
54
55 // Edge-cases 12:00AM and 12:00PM
56 myAlarm.setTime(0,0);
57 assertEquals("12:00AM", myAlarm.toString());
58 myAlarm.setTime(12,0);
59 assertEquals("12:00PM", myAlarm.toString());
60 }
61 }
--------------------------------------------------------------------------
1 public class Alarm {
2
3 private int hour;
4 private int minute;
5
6 /* Constructor to initialize our alarm */
7 public Alarm() {
8 hour = 0;
9 minute = 0;
10 }
11
12 /* Retrieve the hour */
13 public int getHour() {
14 return hour;
15 }
16
17 /* Retrieve the minute */
18 public int getMinute() {
19 return minute;
20 }
21
22 /* Set the alarm time */
23 public boolean setTime(int hr, int min) {
24 if (hr > 23 || hr < 0 || min > 59 || min < 0) {
25 return false;
26 }
27 else {
28 hour = hr;
29 minute = min;
30 return true;
31 }
32 }
33
34 /* Display the time in String format */
35 public String toString() {
36 String tempMin;
37
38 // format special cases
39 if (minute < 10) {
40 tempMin = ":0" + minute;
41 }
42 else {
43 tempMin = ":" + minute;
44 }
45
46 if (hour == 0) {
47 return "12" + tempMin + "AM";
48 }
49 else if (hour == 12) {
50 return "12" + tempMin + "PM";
51 }
52 else if (hour > 12) {
53 return (hour - 12) + tempMin + "PM";
54 }
55 else {
56 return hour + tempMin + "AM";
57 }
58 }
59 }
When we carry out step 4 of the TDD process, we verify that our tests
pass. Step 5 has us refactor to improve readability or structure.
No refactoring is needed at this time. We again finish off with repeating the cycle in step 6. The
previous development example was intended to demonstrate the flow of
TDD. At the end of this lab, you will be able to practice TDD in an
exercise.
3. Why should we use TDD?
By writing tests before code, programmers are forced to differentiate between the functionality to implement and the base condition under which the implementation has to work.
This forces programmers to make better design decisions during
development. Some studies have shown an increase in quality of programs
by a 35-45% reduction in defects. By writing more tests up-front, less
time is spent debugging a solution. Thus, some experiments have found
improvements in productivity for those who develop in a test-first
manner. Surveys from students have indicated an increase in program
understanding and confidence in making changes to code and code
correctness.
4. TDD Exercise
For this exercise you will develop a piggy bank in a TDD fashion. You will create two files: Piggy.java and PiggyTest.java.
You will have to develop the source-code and test-code on your own
computer, and Web-CAT will be used to submit the exercise for grading.
The objective of this assignment
is practice the flow of the test-driven development style.
Unfortunately, for grading purposes we must specify the API of the
piggy bank, so the tests themselves won't be able to bring forth
low-level design decisions. However, it is still good practice to
write the test for how it should work before writing the
implementation. The Piggy.java class has to have the methods listed below. You can assume parameters of amount &ge 0.
- public Piggy() {...} The default constructor should create an empty piggy bank with no coins in it.
- public void addQuarters(int amount) {...} A deposit method to add quarters to the bank.
- public void addDimes(int amount) {...} A deposit method to add dimes to the bank.
- public void addNickels(int amount) {...} A deposit method to add nickels to the bank.
- public void addPennies(int amount) {...} A deposit method to add pennies to the bank.
- public int removeQuarters(int amount) {...}
A withdraw method to remove quarters from the bank. If
successful, it returns the amount of coins requested, if there are not
enough, it returns 0.
- public int removeDimes(int amount) {...} A withdraw method
to remove dimes from the bank. If successful, it returns the amount
of coins requested, if there are not enough, it returns 0.
- public int removeNickels(int amount) {...} A withdraw method
to remove nickels from the bank. If successful, it returns the amount
of coins requested, if there are not enough, it returns 0.
- public int removePennies(int amount) {...} A withdraw method
to remove pennies from the bank. If successful, it returns the amount
of coins requested, if there are not enough, it returns 0.
- public double getTotal() {...} A
method to get the total amount of money in the piggy bank.
- public int getQuarters() {...} Returns the number of quarters in the piggy bank.
- public int getDimes() {...} Returns the number of dimes in the piggy bank.
- public int getNickels() {...} Returns the number of nickels in the piggy bank.
- public int getPennies() {...} Returns the number of pennies in the piggy bank.
4.1. Submission Process
To hand in your files, click on the Submit
tab in Web-CAT. Follow the instructions to upload your files. Remember
that you will need to create a *.zip file with your two Java files (Piggy.java and PiggyTest.java) in it. Web-CAT will automatically extract your two files from the zip archive.
Chetan Desai - cdesai@calpoly.edu