Monday, October 26, 2009

BRUTE FORCE









































Prev don't be afraid of buying books Next






























BRUTE FORCE



The first approach we will explore is to give
our tests direct access to the visual components in the GUI. We can
do this in one of several ways:











  1. make them public instance variables so that the
    test can access them directly











  2. provide an accessor for each component so that
    the test can get hold of them











  3. make the test class an inner class of the class
    that creates the GUI











  4. use reflection to gain access to the
    components











All of these approaches have the drawback that
the components cannot be local to a method; they must be instance
variables. Also, all but the last require extra production code
that is used only for testing.



Since I learned Object Oriented Programming in a
Smalltalk environment, I find the idea of making instance variables
public unthinkable. This rules out option one. Also, I like to keep
my test code separate from production code, so I avoid option
three
as well. The last option is very overhead intensive to do manually. We'll explore some frameworks
later in this chapter that make use of reflection, but hide the
details.



That leaves the second approach: adding
accessors for the components.



Keep in mind that the code was developed
incrementally: enough new test to fail, followed by enough new code
to pass. During development, both the code and the tests were
refactored as needed. Notice how the tests are in two
TestCase classes. Notice the different setUp()
methods.


















As we discuss more fully in the JUnit chapter,
TestCase is a mechanism to group tests that rely on the same
fixture, not tests that happen to use the same class. When we need
a different fixture, we should create a new TestCase class. As you
add tests, add them to the TestCase that maintains the fixture that
they require.
















Given that preamble, here's the test code. First
we have a TestCase that verifies that the required
components are present. Notice how we've used EasyMock. For this
test we aren't concerned with the interaction of the GUI with the
underlying object (i.e., the mock) so we've used
niceControlFor() which provides default implementations
for all of the methods in MovieListEditor.




public class TestWidgets extends TestCase {
private MockControl control;
private MovieListEditor mockEditor;
private MovieListWindow window;


protected void setUp() {
control = EasyMock.niceControlFor(MovieListEditor.class);
mockEditor = (MovieListEditor) control.getMock();
control.activate();
window = new MovieListWindow(mockEditor);
window.init();
window.show();
}

public void testList() {
JList movieList = window.getMovieList();
assertNotNull("Movie list should be non null",movieList);
assertTrue("Movie list should be showing",movieList.isShowing());
}

public void testField() {
JTextField movieField = window.getMovieField();
assertNotNull("Movie field should be non null",movieField);
assertTrue("Movie field should be showing",movieField.isShowing());
}



public void testAddButton() {
JButton addButton = window.getAddButton();
assertNotNull("Add button should be non null",addButton);
assertTrue("Add button should be showing",addButton.isShowing());
assertEquals("Add button should be labeled \"Add\"",
"Add",
addButton.getText());
}

public void testDeleteButton() {
JButton deleteButton = window.getDeleteButton();
assertNotNull("Delete button should be non null",deleteButton);
assertTrue("Delete button should be showing",deleteButton.isShowing());
assertEquals("Delete button should be labeled \"Delete\"",
"Delete",
deleteButton.getText());
}
}






The other TestCase tests for correct
operation of the GUI and uses a more involved mock. Here we build
the mock in each test method, setting different method call
expectations and return values in each. Note, however, the common
mock creation code in setUp().




public class TestOperation extends TestCase {
private static final String LOST IN SPACE = "Lost In Space";
private Vector movieNames;
private MovieListWindow window;
private MockControl control=null;
private MovieListEditor mockEditor = null;


protected void setUp() {
movieNames = new Vector() {
{ add("Star Wars"); add("Star Trek"); add("Stargate"); }
};
window = null;

MockControl control = EasyMock.controlFor(MovieListEditor.class);
MovieListEditor mockEditor = (MovieListEditor) control.getMock();
}

public void testMovieList() {
mockEditor.getMovies();
control.setReturnValue(movieNames, 1);

control.activate();

MovieListWindow window = new MovieListWindow(mockEditor);
window.init();
window.show();



JList movieList = window.getMovieList();
ListModel movieListModel = movieList.getModel();
assertEquals("Movie list is the wrong size",
movieNames.size(),
movieListModel.getSize());

for (int i = 0; i
<
movieNames.size(); i++) {
assertEquals("Movie list contains bad name",
movieNames.get(i),
movieListModel.getElementAt(i));
}

control.verify();
}

public void testAdd() {
Vector movieNamesWithAddition = new Vector(movieNames);
movieNamesWithAddition.add(LOST IN SPACE);

mockEditor.getMovies();
control.setReturnValue(movieNames, 1);

mockEditor.add(LOST IN SPACE);
control.setVoidCallable(1);

mockEditor.getMovies();
control.setReturnValue(movieNamesWithAddition, 1);

control.activate();

MovieListWindow window = new MovieListWindow(mockEditor);
window.init();
window.show();

JTextField movieField = window.getMovieField();
movieField.setText(LOST IN SPACE);

JButton addButton = window.getAddButton();
addButton.doClick();

JList movieList = window.getMovieList();
ListModel movieListModel = movieList.getModel();
assertEquals("Movie list is the wrong size after add",
movieNamesWithAddition.size(),
movieListModel.getSize());

assertEquals("Movie list doesn't contain new name",
LOST IN SPACE,
movieListModel.getElementAt(movieNames.size()));

control.verify();
}

public void testDelete() {
Vector movieNamesWithDeletion = new Vector(movieNames);
movieNamesWithDeletion.remove(1);



mockEditor.getMovies();
control.setReturnValue(movieNames, 1);

mockEditor.delete(1);
control.setVoidCallable(1);

mockEditor.getMovies();
control.setReturnValue(movieNamesWithDeletion, 1);

control.activate();

MovieListWindow window = new MovieListWindow(mockEditor);
window.init();
window.show();

JList movieList = window.getMovieList();
movieList.setSelectedIndex(1);

JButton deleteButton = window.getDeleteButton();
deleteButton.doClick();

ListModel movieListModel = movieList.getModel();
assertEquals("Movie list is the wrong size after delete",
movieNamesWithDeletion.size(),
movieListModel.getSize());

control.verify();
}
}






The GUI class is below, with a screen shot of
the resulting window shown in Figure 8.2.




public class MovieListWindow extends JFrame {
private JList movieList;
private JButton addButton;
private MovieListEditor myEditor;
private JTextField movieField;
private JButton deleteButton;

public MovieListWindow(MovieListEditor anEditor) {
super();
myEditor = anEditor;
}

public JList getMovieList() {
return movieList;
}

public JTextField getMovieField() {
return movieField;
}

public JButton getAddButton() {
return addButton;
}



public JButton getDeleteButton() {
return deleteButton;
}

public void init() {
setLayout();
initMovieList();
initMovieField();
initAddButton();
initDeleteButton();
pack();
}

private void setLayout() {
getContentPane().setLayout(new FlowLayout());
}

private void initMovieList() {
movieList = new JList(getMovies());
JScrollPane scroller = new JScrollPane(movieList);
getContentPane().add(scroller);
}

private void initMovieField() {
movieField = new JTextField(16);
getContentPane().add(movieField);
}

private void initAddButton() {
addButton = new JButton("Add");
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myEditor.add(movieField.getText());
movieList.setListData(getMovies());
}
});
getContentPane().add(addButton);
}

private void initDeleteButton() {
deleteButton = new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myEditor.delete(movieList.getSelectedIndex());
movieList.setListData(getMovies());
}
});
getContentPane().add(deleteButton);
}











private Vector getMovies() {
Vector movies = myEditor.getMovies();
return (movies == null) ? new Vector() : movies;
}
}










Figure 8.2. The resulting GUI.




























































Amazon






No comments: