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:
  1. Add a new test for an unimplemented unit of functionality.
  2. Run all previously written tests and see the newly added test fail.
  3. Write code that implements the new functionality.
  4. Run all tests and see them succeed.
  5. Refactor (rewrite to improve readability or structure).
  6. 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.

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