Test Driven Design with JUnit: An Introduction

This activity is a high-level introduction to Test Driven Design and the use of JUnit. Consult the on-line references listed on the course site for more in-depth coverage of these topics. The following example was taken from Test-Driven Development, A Practical Guide by David Astels.

The Movie Management System

This system will make it easy for a user to keep track of movies they want to see. Additionally it will provide support for ratings, recommendations, etc. to help in deciding what to watch.

Sample User Stories:

  1. Movie List – Provide a way to keep a list of movies and add movies to it. Ordering of the list is not a concern.
  2. Movies Can Be Renamed – Provide a way to rename movies that are in the list.
  3. Movies Are Unique – A movie appears only once in the list; the names are unique and case-insensitive. Attempts to add a duplicate should fail and result in an error.

( and so on….)

For the purpose of our exercise, lets start with the implementation of the first user story – “Movie List”. The first step is to break the story into tasks:

·      Task 1-1 Make a container for movies with a way to add to it. Doesn’t have to be ordered or sorted.

·      Task 1-2 Make a GUI that shows a list of movies. List order represents the order of the underlying collection. List should scroll as required.

·      Task 1-3 Provide a GUI interface for adding movies to the list.

Note that the tasks break the user story down into a set of activities starting with the underlying data structure and associated behavior and then adds a user interface.

Test Driven Design

Let’s implement Task 1-1. The first step using TDD is to begin with a single test, implement (ONLY) the code needed to pass the test and move on The rule is to test the simple stuff first and implement only what you need to satisfy the test condition – and no more. Here are our tests for Task 1-1.

·         Test 1 – An empty list of movies should have a size of zero.

·         Test 2 – Adding a movie to an empty list should result in a list with a size of one.

·         Test 3 – Adding two movies to an empty list should result in a list with a size of two.

·         Test 4 – If we add a movie to a list, we should be able to ask if it’s there. Conversely, we should receive a negative response when we ask about a movie we haven’t added.

We start our testing, using the Eclipse support for JUnit:

  1. Create a new Java project “MovieManager”.

Test 1 - An empty list of movies should have a size of zero.

  1. Create a class to hold the movies – MovieList
  2. Create a class to hold the test cases for MovieListMovieListTest. Use the JUnit Wizard in Eclipse to set up the test class:
    1. On the Eclipse tool bar there are a number of wizard icons, highlight the MovieList class and select the icon “Test Case” (use the pull down arrow next to the green ‘C’ icon) to start the JUnit Wizard.
    2. The wizard will create the MovieListTest class for you. Be sure that “New JUnit 3  Test” is checked (not JUnit4) and that the check box for creating a constructor stub is checked. Hit Finish to complete the running of the wizard.
    3. The first time you use the JUnit wizard, you will be prompted to add the Junit jar file to your project build path.
  3. The first test will verify that an empty movie list returns a size of zero. Add the following method to MovieListTest:

public void testEmptyListSize(){

MovieList emptyList = new MovieList();

assertEquals( "Size of empty list should be 0.", 0, emptyList.size());

}

  1. We have just created a test case in JUnit. Every test case method must start with the word “test”. The rest of the method name should have some meaningful relationship to the type of test being performed.
  2. Note that MovieListTest doesn’t compile – there is no size method in MovieList. Try clicking the light bulb symbol on the line with the error. You get a box of suggested fixes. Double-click on “create method size” and Eclipse will generate the method for you in MovieList.
  3. Edit the size() method to return an int and the statement return 0. Why 0? Remember we are only trying to satisfy the test and nothing more.
  4. Now we will run the test:
    1. Select MovieListTest and Run as -> JUnit test. JUnit will then execute each test case method in MovieListTest by looking for methods that start with “test”. A view should appear showing the results of the test. If you don’t see it, try Window->Show View->Other->Java->JUnit.
    2. If you get a java.lang.UnsupportedClassVersionError: Bad version number in .class file  error, make sure you are using Java 5.0 as your compiler (Window>Preferences>Java>Compiler or right-click on the project and select Properties>Java Compiler).
    3. You should see a green bar indicating your test ran successfully. To see a test fail, change the assertEquals expected condition to 1. The failure trace will identify the assert that failed. Remember to change the constant back to 0!

Test 2 – Adding a movie to an empty list should result in a list with size of one.

  1. Add a new test method – testSizeAfterAddingOne() :

public void testSizeAfterAddingOne(){

MovieList oneItemList = new MovieList();

oneItemList.add( starWars);

assertEquals( "Size of one item list should be 1.", 1, oneItemList.size());

}

  1. We need to define the variable starWars. It is a type of thing that will be added to the MovieList, so lets create a Movie class and, in our test case, declare starWars as a Movie object (just before oneItemList.add(starWars):

Movie starWars = new Movie();

  1. We also need to define the method add in MovieList. Use the same technique we used for size():

public void add( Movie movieToAdd) {
}

  1. Everything should compile at this point. Run the tests and you should get an error expecting a value of 1, but getting a zero. We need to return a size of 1. Modify the add method to set the count of movies to one (note  we need to create a count instance variable)

private int count = 0

public void add( Movie movieToAdd) {

count = 1;

}

Also change:

public int size() {

return count;

}

It looks fishy to fix the count at one for the add method, but we only need to satisfy the current test condition – and nothing more! Don’t look ahead, that’s how defects creep in.

Run the tests – should be all green. Note that the first test still passes, which indicates that we did not break anything that was already working.

Test 3 – Adding two movies to an empty list should result in a list with a size of two.

  1. We know it works for zero and one , so if works for two we can assume it will work for anything. Add a new test method testSizeAfterAddingTwo():

public void testSizeAfterAdddingTwo(){
     Movie starWars = new Movie();
     Movie starTrek = new Movie();
     MovieList twoItemList = new MovieList();
     twoItemList.add(starWars);
     twoItemList.add(starTrek);
     assertEquals("Size of a two item list should be 2.", 2, twoItemList.size());
}

Of course this fails. Now is the time to modify the add() method in MovieList:

public void add( Movie movieToAdd){
    count ++;
}

2.      Run the tests again – all green, including previous two tests.

3.      Before moving on, lets do some “refactoring” – making the code easier to read and maintain. The variable name count is a little weak; lets make it more descriptive by renaming it numberOfMovies.

4.      Eclispe has a rename feature that will go through and change all occurrences of a variable, class or method without you having to manually hunt for all the changes.

a.      Highlight the variable count and right select Refactor->Rename.

b.      You can put in the new name and optionally see a preview of what will be changed.

5.      After making the change, rerun the test to see the green bar. Rerun the tests after ANY change you make to your code – it’s easy once the test case are in place, and you’ll gain confidence that your changes haven’t broken anything.

Test 4 –  If we add a movie to a list, we should be able to ask if it’s there. Conversely, we should receive a negative response when we ask about a movie we haven’t added.

1.      Try this one on your own. You will need to use the JUnit methods assertTrue() and assertFalse() to test the presence of movies you add.

2.      Hint: You will also need to think about a Collection of some sort to hold movies (we can’t postpone doing real work forever!)..

Conclusion

To explore JUnit a bit further, download the final solution is in MovieManager.zip, unpack this, and import the code into Eclipse.

Note this version uses the setUp() method in MovieListTest which is executed prior to the start of each individual test case. This is useful for centralizing repeated work that needs to be done prior to each test execution. Note the use of instance variables in MovieListTest to support the setUp() method.

JUnit also supports a tearDown() method that may be run at the conclusion of each test to cleanup.