EDIT THE RATING
Allow the rating to be edited.
For this task, we'll need the following tests:
Test 31. Selecting a movie updates the rating in the GUI.
Test 32. Updating a movie changes its rating if a different rating was selected for it.
Test 33. Selecting a movie from the list updates the displayed rating.
Test 34. Updating a movie in the GUI changes its rating if a different rating was selected for it, and updates the display accordingly.
We'll start by adding some ratings to TestMovieListEditor's fixture:
starWars = new Movie("Star Wars",5); starTrek = new Movie("Star Trek",3); stargate = new Movie("Stargate");
Test 31: Selecting a movie updates the rating in the GUI
Next we'll extend testSelecting() to check that a selection in the movie list causes an update of the rating:
public void testSelecting() { mockView.setMovies(movies); control.setVoidCallable(1);
mockView.setNewName("Star Wars"); control.setVoidCallable(1); mockView.setNewRating(6); control.setVoidCallable(1);
mockView.setNewName("Star Trek"); control.setVoidCallable(1); mockView.setNewRating(4); control.setVoidCallable(1);
mockView.setNewName("Stargate"); control.setVoidCallable(1); mockView.setNewRating(0); control.setVoidCallable(1);
control.activate();
MovieListEditor editor = new MovieListEditor(movieList,mockView); editor.select(0); editor.select(1); editor.select(2);
control.verify(); }
The first step to getting to a green bar again is to add a method to the MovieListEditorView interface:
public interface MovieListEditorView { void setMovies(Vector movies); String getNewName(); void setEditor(MovieListEditor anEditor); void setNewName(String string); void duplicateException(String string); void setNewRating(int i); }
Next, we need to add to MovieListEditor.select() to set the rating as well as the name:
public void select(int i) { if (i == -1) { selectedMovie = null; } else { selectedMovie = movies.getMovie(i); view.setNewName(selectedMovie.getName());
try { view.setNewRating(selectedMovie.getRating() + 1); } catch (UnratedException e) { view.setNewRating(0); } } }
Now we see that several tests are failing due to the additional (and unexpected) calls to setNewRating(). We can either add expectations to these tests or have them ignore those calls. We'll do the latter since it's the simplest thing that will work. We just need to add the following line to the beginning of each failing test:
mockView.setNewRating(0); control.setDefaultVoidCallable();
Upon looking over the code, I feel that some renaming is in order. The method for getting and setting the name and rating fields are misleading. Let's change them as so: getNewName() changes to getNameField().For brevity, we'll just show the interface:
public interface MovieListEditorView { void setMovies(Vector movies); String getNameField(); void setEditor(MovieListEditor anEditor); void setNameField(String string); void duplicateException(String string); void setRatingField(int i); }
Test 32: Updating a movie changes its rating if a different rating was selected for it
Now for the flip side of editing the rating...updating the movie behind it. We'll start by extending testUpdating() by adding ratings to the Movies we create and adding expectations for calls to setRatingField() and getRatingField():
public void testUpdating() { Vector newMovies = new Vector(); newMovies.add(starWars); newMovies.add(new Movie("Star Trek I",5)); newMovies.add(stargate);
mockView.setMovies(movies); control.setVoidCallable(1);
mockView.setNameField("Star Trek"); control.setVoidCallable(1); mockView.setRatingField(4); control.setVoidCallable();
mockView.getNameField(); control.setReturnValue("Star Trek I",1); mockView.getRatingField(); control.setReturnValue(6, 1);
mockView.setMovies(newMovies); control.setVoidCallable(1);
control.activate();
MovieListEditor editor = new MovieListEditor(movieList,mockView); editor.select(1); editor.update();
control.verify(); }
To get to green, we have to do some work on MovieListEditor.update(). We'll add a line that sets the rating of the selected Movie if it can be renamed successfully:
public void update() { if (selectedMovie != null) { String newName = view.getNameField();
try { movies.rename(selectedMovie, newName); selectedMovie.setRating(view.getRatingField()); updateMovieList(); } catch (DuplicateMovieException e) { view.duplicateException(newName); } } }
Now we need to add a setRating() method to Movie. We won't test-drive that, as it will be a simple mutator and it will be tested indirectly. In fact, I won't even bother showing it here. Most IDEs will have a way to generate accessors and mutators for instance variables.
Green bar. Now we can turn to the Swing layer. We can take the same approach to editing the rating as to editing the name: When a movie is selected, use a field to edit its value. In this case, since the range is constrained, we'll use a combo box.
We'll start by adding some ratings to the fixture:
starWars = new Movie("Star Wars",5); starTrek = new Movie("Star Trek",3); stargate = new Movie("Stargate");
Green bar. All the tests still work. We can continue.
Test 33: Selecting a movie from the list updates the displayed rating
We'll start with a test to check that selecting a movie in the list sets the rating selection combo box to the appropriate value:
public void testSelectUpdatesRating() { JListOperator movieList = new JListOperator(mainWindow); JComboBoxOperator ratingCombo = new JComboBoxOperator(mainWindow);
movieList.clickOnItem(0, 1); assertEquals("wrong rating from selecting starWars.", 6, ratingCombo.getSelectedIndex());
movieList.clickOnItem(1, 1); assertEquals("wrong rating from selecting starTrek.", 4, ratingCombo.getSelectedIndex());
movieList.clickOnItem(2, 1); assertEquals("wrong rating from selecting stargate.", 0, ratingCombo.getSelectedIndex()); }
Now we need to make it pass. We need a combo box in the GUI and methods to set and get its value:
private JComboBox ratingField = null;
public void setRatingField(int i) { ratingField.setSelectedIndex(i); }
public int getRatingField() { return ratingField.getSelectedIndex(); }
public void init() { setTitle(); setLayout(); initList(); initField(); initRatingCombo(); initAddButton(); initUpdateButton(); pack(); }
private void initRatingCombo() { ratingField = new JComboBox(CustomMovieListRenderer.icons()); getContentPane().add(ratingField); }
Green bar. OK. We talk to the customer. We need to be able to select a movie, change the rating, and click update. We try it. Uh oh. We get the duplicate movie message. Hmmm... think think... talk talk... what we need to do is raise that error only if the update makes the selected movie equal to a different movie in the list.
We need to go back to TestMovieListEditor and create a test to drive that behavior:
public void testUpdatingWithSameName() { Vector newMovies = new Vector(); newMovies.add(starWars); newMovies.add(new Movie("Star Trek",5)); newMovies.add(stargate);
mockView.setMovies(movies); control.setVoidCallable(1);
mockView.setNameField("Star Trek"); control.setVoidCallable(1); mockView.setRatingField(4); control.setVoidCallable();
mockView.getNameField(); control.setReturnValue("Star Trek",1); mockView.getRatingField(); control.setReturnValue(6, 1);
mockView.setMovies(newMovies); control.setVoidCallable(1);
control.activate();
MovieListEditor editor = new MovieListEditor(movieList,mockView); editor.select(1); editor.update();
control.verify(); }
Now we can tweak the MovieListEditor.update() method to make the bar green again:
public void update() { if (selectedMovie != null) { String newName = view.getNameField(); if (selectedMovie.getName().equals(newName)) { updateMovie(); } else {
try { movies.rename(selectedMovie, newName); updateMovie(); } catch (DuplicateMovieException e) { view.duplicateException(newName); } } } }
private void updateMovie() { selectedMovie.setRating(view.getRatingField() - 1); updateMovieList(); }
Notice that we did some refactoring while we were there.
Test 34: Updating a movie in the GUI changes its rating if a different rating was selected for it, and updates the display accordingly
Now back to the Swing GUI. We need a test that selects a movie, changes the rating, and updates:
public void testUpdateRating() { JListOperator movieList = new JListOperator(mainWindow); JComboBoxOperator ratingCombo = new JComboBoxOperator(mainWindow); movieList.clickOnItem(0, 1); ratingCombo.setSelectedIndex(4);
JButtonOperator updateButton = new JButtonOperator(mainWindow, "Update"); updateButton.pushNoBlock(); movieList.clickOnItem(1, 1); movieList.clickOnItem(0, 1); assertEquals("updating should have changed rating.", 4, ratingCombo.getSelectedIndex()); }
Green bar. Life is good. Finally, Figure 13.2 shows the current state of the GUI.
|
No comments:
Post a Comment