Developing Custom Swing Components With Test Driven Development
By Santosh Shanbhag, OCI Senior Software Engineer
January 2005
Introduction
Developing Swing components while staying on the path of test driven development has no doubt challenged many seasoned Swing developers. Many aspects of GUI testing are indeed not that complicated as long as one adopts the simplicity principle. Moreover, there are quite a few Swing testing frameworks that make it easier to test Swing applications - Abbot and Jemmy being amongst the most popular. This article focuses on developing a couple of custom Swing GUI components using test driven techniques. We will also develop a simple GUI testing helper class that will aid us in testing our custom components. This article does not cover any GUI testing framework and the reader is advised to look them up elsewhere.
Custom Swing Component #1 - A Searchable List Box
A searchable list box provides capability to search a list box for a particular item. The user enters some text in the provided search box. For each keystroke, the list box automatically scrolls down and selects the closest match it has found so far. If a match is not found, the list box does not select anything. The searchable list box is shown in Fig 1.
Figure 1. Searchable List Box
Figure 2. Searchable List Box With "United S" typed
Test Driven Development
Keeping a simple approach to development, the initial coding provides a simple SearchableListBox
that extends JPanel
and is composed of three sub-components: a JLabel
that displays a custom text like "Search" or "Find", a JTextField
of default length 30 that allows the user to type in the search text, and a list box that contains the list of items that could be searched. There is no functionality at this point other than the basic layout of the components. A simple unit test using the JUnit framework ( http://www.junit.org ) tests the basic display of the panel. There are no asserts yet - just a visual check. The display is shown in Figure 1 above.
JUnit Test: SearchableListBox_UT.java
- /*
- * Author: Santosh Shanbhag
- */
- package com.ociweb.testinggui;
-
- import junit.framework.TestCase;
-
- import javax.swing.*;
-
- public class SearchableListBox_UT extends TestCase {
-
- // String based test data that is used to populate the list items
- public static final String[] LIST_DATA = new String[]{
- "United Kingdom", "Italy", "India", "Uganda", "Austraila",
- "United States", "Austria", "Indonesia"};
-
- public SearchableListBox_UT(String name) {
- super(name);
- }
-
- /**
- * Initial Test to check display of components.
- * This test is useful only initially when we are designing the component. It helps us to verify
- * visually that the screen layout of the component is proper. In an automated test environment, it is
- * advisable to comment out this test before commiting the code
- *
- */
- public void testDisplay() throws Exception {
- JFrame frame = new JFrame();
- SearchableListBox searchableListBox = new SearchableListBox(LIST_DATA);
- frame.getContentPane().add(searchableListBox);
- frame.pack();
- frame.setLocationRelativeTo(null);
- frame.setVisible(true);
- // sleep for 60 seconds so that you can check the display
- Thread.sleep(60000);
-
- }
- }
Code: SearchableListBox.java
- /*
- * Author: Santosh Shanbhag
- */
- package com.ociweb.testinggui;
-
- import javax.swing.*;
- import java.awt.*;
-
- public class SearchableListBox extends JPanel {
-
- // default search label text
- public static final String SEARCH_LABEL_DEFAULT_TEXT = "Search:";
-
- // default search field length
- public static final int SEARCH_FIELD_DEFAULT_LENGTH = 30;
-
- private JLabel searchLabel;
- private JTextField searchField;
- private JList list;
-
-
- /**
- * Constructor.
- * @param listData The list box items
- */
- public SearchableListBox(Object[] listData) {
- init(this.searchLabelTxt, this.searchFieldLength, listData);
- }
-
- /**
- * Constructor.
- * @param searchLabelTxt
- * The text used to display above the search field. For example: "Search", "Find", "Get it"
- * @param searchFieldLength
- * The length of the search field
- * @param listData
- * The list box items
- */
- public SearchableListBox(String searchLabelTxt, int searchFieldLength, Object[] listData) {
- init(searchLabelTxt, searchFieldLength, listData);
- }
-
-
- /**
- * Initialization routine to create GUI components.
- * @param searchLabelTxt
- * The text used to display above the search field. For example: "Search", "Find", "Get it"
- * @param searchFieldLength
- * The length of the search field
- * @param listData
- * The list box items
- */
- private void init(String searchLabelTxt, int searchFieldLength, Object[] listData) {
- searchLabel = new JLabel(searchLabelTxt);
- searchField = new JTextField(searchFieldLength);
- list = new JList(listData);
-
- // we would like to see the first ten items
- list.setVisibleRowCount(10);
-
- // limit the selection to a single item
- list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- layoutComponents();
- }
-
- /**
- * Lays out GUI components on the screen.
- */
- private void layoutComponents() {
- setLayout(new BorderLayout());
-
- // create a search panel to contain search label and
- // search field.
- JPanel searchPanel = new JPanel(new BorderLayout());
- searchPanel.add(searchLabel, BorderLayout.NORTH);
- searchPanel.add(searchField, BorderLayout.SOUTH);
-
- // put list box in the scroll pane
- JScrollPane scrollpaneForList = new JScrollPane(list,
- JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
- JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
-
- add(searchPanel, BorderLayout.NORTH);
- add(scrollpaneForList, BorderLayout.CENTER);
- }
-
- }
Testing the construction non-visually
At this point we are probably satisfied with the basic display and are ready to implement the search functionality. However, we still need an additional test that will verify if anything breaks in the basic construction of the component. So we add another test to the UT class as shown below. We also have a GUITestHelper
class that has static methods to help us with the testing. The code for the GUITestHelper
is provided at the end of this article. We still have no way of finding out if the components are laid out correctly but rely instead on the visual test.
- public void testConstruction() throws Exception {
-
- // for testing, use "Find" text instead of the default "Search"
- String searchLabelTxt = "Find";
- int searchFieldLength = 20;
-
- SearchableListBox searchableListBox = new SearchableListBox(searchLabelTxt, searchFieldLength, LIST_DATA);
-
- // find out if a JLabel with "Find" text is contained in the custom component
- JLabel searchLabel = GUITestHelper.findJLabelContainingText(searchableListBox, searchLabelTxt);
- assertNotNull("Could not find a JLabel with text: " + searchLabelTxt, searchLabel);
-
- // find out if a JTextField of length 20 is contained in the custom component
- JTextField textField = GUITestHelper.findJTextFieldOfLength(searchableListBox, searchFieldLength);
- assertNotNull("Could not find a JTextField of length: " + searchFieldLength, textField);
-
- // test that the list contains same number of items that were passed in
- assertEquals(LIST_DATA.length, searchableListBox.getItemCount());
-
- // As of now, test that the list maintains the order of the items that were passed in.
- // But in the future, if someone sorts the order of the items in the list, this test
- // will need to be updated. At that time, the updated test will ensure that the code
- // that keeps the list items in a sorted order is not broken.
- for (int i = 0; i < LIST_DATA.length; i++) {
- String expectedListItem = LIST_DATA[i];
- assertEquals("List Item not in the order it was passed in",
- expectedListItem, searchableListBox.getItemAt(i));
- }
-
- }
Implementing the search functionality
The next step is to test and implement the search functionality. The JTextField
stores it's data in a model whose class is javax.swing.text.Document
. A document listener object (javax.swing.event.DocumentListener
) can be associated with the Document
that intercepts insertions, deletions, and changes made to it. We define our DocumentListener
class as shown below:
- /*
- * Custom document listener class that is used by SearchableListBox to intercept text field changes.
- * Just to make sure all implemented methods call doUpdate().
- *
- * Author: Santosh Shanbhag
- */
- package com.ociweb.testinggui;
-
- import javax.swing.event.DocumentListener;
-
- public abstract class CustomDocumentListener implements DocumentListener {
-
- public void changedUpdate(DocumentEvent e) {
- doUpdate();
- }
-
- public void insertUpdate(DocumentEvent e) {
- doUpdate();
- }
-
- public void removeUpdate(DocumentEvent e) {
- doUpdate();
- }
-
- public abstract void doUpdate();
-
- }
Now all we have to do is plug this document listener to the JTextField
's Document
model and implement the doUpdate()
method. The doUpdate()
method will implement the search functionality. We create an inner class in SearchableListBox
that extends CustomDocumentListener
so that the listener has access to both the search text field and the list box. This is shown in the code below:
- private void init(String searchLabelTxt, int searchFieldLength, Object[] listData) {
- this.listData = listData;
- list = new JList(listData);
-
- searchLabel = new JLabel(searchLabelTxt);
- searchField = new JTextField(searchFieldLength);
-
- // we would like to see the first ten items
- list.setVisibleRowCount(10);
-
- // limit the selection to a single item
- list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
- // add a document listener to the text field
- SearchFieldDocumentListener searchFieldListener = new SearchFieldDocumentListener();
- searchField.getDocument().addDocumentListener(searchFieldListener);
-
-
- // lay out GUI components
- layoutComponents();
- }
-
- // returns the currently selected item in the list box
- public Object getSelectedItem() {
- return list.getSelectedValue();
- }
-
- //******* inner class of SearchableListBox
- class SearchFieldDocumentListener extends CustomDocumentListener {
-
- public void doUpdate() {
- doSearch();
- }
-
- }
The SearchFieldDocumentListener
implements the doUpdate()
method by making a call to the doSearch()
method in the SearchableListBox
class. This keeps the listener code from referring any objects of SearchableListBox
directly thus reducing dependency between the two classes. Next we have to write a test to make sure that doSearch()
implementation is correct. This is shown below:
- public void testSearchImplementation() throws Exception {
-
- String[] LIST_ITEMS = new String[]{
- "United Kingdom", "Italy", "India", "Uganda", "Australia", "Chile", "Brazil", "United States", "Austria",
- "Indonesia", "Indiana", "Oklahoma", "New Jersey", "New Hampshire", "Africa"};
-
- SearchableListBox searchableListBox = new SearchableListBox(LIST_ITEMS);
-
- // get a handle on the search text field
- int searchFieldDefaultLength = SearchableListBox.SEARCH_FIELD_DEFAULT_LENGTH;
- JTextField textField = GUITestHelper.findJTextFieldOfLength(searchableListBox, searchFieldDefaultLength);
- assertNotNull("Could not find a JTextField of length: " + searchFieldDefaultLength, textField);
-
-
- textField.setText("Austri");
- searchableListBox.getSelectedItem();
- assertEquals("Austria", searchableListBox.getSelectedItem());
-
- textField.setText("Austra");
- searchableListBox.getSelectedItem();
- assertEquals("Australia", searchableListBox.getSelectedItem());
-
- textField.setText("Af");
- searchableListBox.getSelectedItem();
- assertEquals("Africa", searchableListBox.getSelectedItem());
-
- textField.setText("United");
- searchableListBox.getSelectedItem();
- assertEquals("United Kingdom", searchableListBox.getSelectedItem());
-
- textField.setText("United K");
- searchableListBox.getSelectedItem();
- assertEquals("United Kingdom", searchableListBox.getSelectedItem());
-
- textField.setText("United S");
- searchableListBox.getSelectedItem();
- assertEquals("United States", searchableListBox.getSelectedItem());
-
- textField.setText("New");
- searchableListBox.getSelectedItem();
- assertEquals("New Jersey", searchableListBox.getSelectedItem());
-
- textField.setText("New H");
- searchableListBox.getSelectedItem();
- assertEquals("New Hampshire", searchableListBox.getSelectedItem());
-
- textField.setText("Ug");
- searchableListBox.getSelectedItem();
- assertEquals("Uganda", searchableListBox.getSelectedItem());
- }
Finally the implementation of the doSearch()
method is shown below:
- private void doSearch() {
-
- // find the closest matching item
- int searchItemIndex = findSearchItemIndex(list, searchField.getText());
-
- // clear any previous selections
- list.clearSelection();
-
- list.setSelectedIndex(searchItemIndex);
-
- // scroll down to make sure the selected item is visible
- list.ensureIndexIsVisible(Math.max(searchItemIndex, 0));
- }
-
- private int findSearchItemIndex(JList inputList, String searchString) {
-
- // if there is nothing in the search text field just return -1
- if ("".equals(searchString)) return -1;
-
- int indexOfSearchedItem = -1;
- for (int i = 0; i < listData.length; i++) {
- String listItemString = listData[i].toString();
-
- // if the search string is contained at the start of the list item string, we found it!!!
- if (listItemString.indexOf(searchString) == 0) {
- indexOfSearchedItem = i;
- break;
- }
- }
-
- // make sure we never go out of array bounds
- return Math.min(indexOfSearchedItem, listData.length - 1);
- }
Custom Swing Component #2 - Two List Boxes With Inter-Transferable Items
Here we design and test a component that has two list boxes and two buttons. When the first button is clicked, the selected item from the first list box is transferred to the second. When the second button is clicked, the selected item from the second list box is transferred to the first. These are the basic requirements of this component. The component is shown in figure 3 below.
Figure 3. Two List Boxes With Inter-Transferable Items
Test Driven Development
Keeping a simple approach to development just like for SearchableListBox
before, the intial coding provides a simple component ListBoxesWithTransferableItems
that extends JPanel
and is composed of six sub-components: two JLabels
that display a text for each list box, two J Buttons
one for transfer from left-to-right and vice- versa, and two JLists
. There is no functionality at this point other than the basic layout of the components. A simple unit test using the JUnit framework tests the basic display of the panel. There are no asserts yet - just a visual check. The display is shown in Figure 3 above.
JUnit Test: ListBoxesWithTransferableItems_UT.java
- /*
- * UT class for testing ListBoxesWithTransferableItems.
- *
- * Author: Santosh Shanbhag
- */
- package com.ociweb.testinggui;
-
- import junit.framework.TestCase;
-
- import javax.swing.*;
- import java.awt.*;
-
- public class ListBoxesWithTransferableItems_UT extends TestCase {
-
- public ListBoxesWithTransferableItems_UT(String name) {
- super(name);
- }
-
- /**
- * Initial Test to check display of components.
- * This test is useful only initially when we are designing the component. It helps us to verify
- * visually that the screen layout of the component is proper. In an automated test environment, it is
- * advisable to comment out this test before committing the code
- *
- */
- public void testDisplay() throws Exception {
- String[] LIST_DATA_LEFT = {"Apples", "Bananas", "Oranges", "Grapes", "WaterMelons", "HoneyDew", "Nectarines"};
- String[] LIST_DATA_RIGHT = {"Peaches", "Cantaloupes", "Figs"};
- ListBoxesWithTransferableItems listBoxesWithTransferableItems
- = new ListBoxesWithTransferableItems(LIST_DATA_LEFT, LIST_DATA_RIGHT);
- listBoxesWithTransferableItems.setBorder(BorderFactory.createLineBorder(Color.black));
-
- // create a test frame to show the panel
- JFrame frame = new JFrame();
- frame.getContentPane().add(listBoxesWithTransferableItems);
- frame.pack();
-
- // center the frame on the screen
- frame.setLocationRelativeTo(null);
- frame.show();
-
- // 1-minute delay to see the component
- Thread.sleep(60000);
-
- }
- }
Code: ListBoxesWithTransferableItems.java
- /*
- * GUI Component that has two list boxes with items that can be transferred between them.
- *
- * Author: Santosh Shanbhag
- */
- package com.ociweb.testinggui;
-
- import javax.swing.*;
- import java.awt.*;
-
- public class ListBoxesWithTransferableItems extends JPanel {
-
- // label that will be displayed above the left list box
- private JLabel labelForLeftListBox = new JLabel("Left List Box");
-
- // label that will be displayed above the right list box
- private JLabel labelForRightListBox = new JLabel("Right List Box");
-
- private JList leftListBox;
- private JList rightListBox;
-
- // on clicking, items will be transferred from left to right list box
- private JButton transferFromLeftToRightButton = new JButton(">>");
-
- // on clicking, items will be transferred from right to left list box
- private JButton transferFromRightToLeftButton = new JButton("<<");
-
- /**
- * Constructor.
- *
- * @param listDataForLeftList - data for left side list box
- * @param listDataForRightList - data for right side list box
- */
- public ListBoxesWithTransferableItems(Object[] listDataForLeftList, Object[] listDataForRightList) {
- init(listDataForLeftList, listDataForRightList);
- }
-
- /**
- * Constructor.
- *
- * @param listDataForLeftList - data for left side list box
- * @param listDataForRightList - data for right side list box
- * @param leftListBoxLabelTxt - label text for left side list box
- * @param rightListBoxLabelTxt - label text for right side list box
- */
- public ListBoxesWithTransferableItems(Object[] listDataForLeftList, Object[] listDataForRightList,
- String leftListBoxLabelTxt, String rightListBoxLabelTxt) {
- labelForLeftListBox.setText(leftListBoxLabelTxt);
- labelForRightListBox.setText(rightListBoxLabelTxt);
- init(listDataForLeftList, listDataForRightList);
- }
-
- private void init(Object[] listDataForLeftList, Object[] listDataForRightList) {
- leftListBox = new JList(listDataForLeftList);
- rightListBox = new JList(listDataForRightList);
- layoutComponents();
- }
-
- // use a layout manager to lay out sub components in the panel
- private void layoutComponents() {
- add(createPanelForListBoxWithLabel(leftListBox, labelForLeftListBox));
- JPanel buttonPanel = new JPanel(new BorderLayout());
- buttonPanel.add(transferFromLeftToRightButton, BorderLayout.NORTH);
- buttonPanel.add(transferFromRightToLeftButton, BorderLayout.SOUTH);
- add(buttonPanel);
- add(createPanelForListBoxWithLabel(rightListBox, labelForRightListBox));
- }
-
- // create a panel with label displayed above the list box.
- // put list box in a scroll pane.
- private JPanel createPanelForListBoxWithLabel(JList listBox, JLabel label) {
- JPanel panel = new JPanel(new BorderLayout());
- panel.add(label, BorderLayout.NORTH);
- JScrollPane scrollPaneForListBox = new JScrollPane(listBox);
- panel.add(scrollPaneForListBox, BorderLayout.CENTER);
- return panel;
- }
-
- }
The GUI has no functionality yet so we move on to the next step. The JButtons
need an ActionListener
that will act on the list boxes (transferring an item from one to the other) when clicked. Using an inner class as the listener we provide a method stub in the ListBoxesWithTransferableItems
class that will be called every time a button is clicked. This is shown in the code below (ListBoxesWithTransferableItems.java
).
- private void transferSelectedItemFromRightListBoxToLeft() {
- }
-
- private void transferSelectedItemFromLeftListBoxToRight() {
- }
-
- /**
- * ******* Inner Class *************
- */
- class ButtonActionListener implements ActionListener {
-
- public void actionPerformed(ActionEvent e) {
-
- JButton sourceButton = (JButton) e.getSource();
-
- if (sourceButton == transferFromLeftToRightButton) {
-
- // transfer from left to right
- transferSelectedItemFromLeftListBoxToRight();
- }
- else if (sourceButton == transferFromRightToLeftButton) {
-
- // transfer from right to left
- transferSelectedItemFromRightListBoxToLeft();
- }
- }
- }
Since we are following test driven development, we should write a unit test at this point to verify that selected items will be transferred from one list box to the other when the appropriate buttons are clicked. Here's the test for transferring from left list to right list By making slight changes, we can easily write another test that verifies the transfer of items from right-to-left. The code is provided in the listing at the bottom.
- public void testTransferItemsFromLeftListToRightList() throws Exception {
-
- ListBoxesWithTransferableItems listBoxesWithTransferableItems
- = new ListBoxesWithTransferableItems(LIST_DATA_LEFT, LIST_DATA_RIGHT);
-
- JButton leftToRightTransferButton = GUITestHelper.findButtonWithText(listBoxesWithTransferableItems, ">>");
- assertNotNull(leftToRightTransferButton);
-
- // assert that left list contains expected data
- Object[] leftListData = listBoxesWithTransferableItems.getAllItemsFromLeftListBox();
- assertTrue(Arrays.equals(LIST_DATA_LEFT, leftListData));
-
- // assert that right list contains expected data
- Object[] rightListData = listBoxesWithTransferableItems.getAllItemsFromRightListBox();
- assertTrue(Arrays.equals(LIST_DATA_RIGHT, rightListData));
-
- // click the left-to-right transfer button
- leftToRightTransferButton.doClick();
-
- // there was nothing selected in left list, so nothing should be removed from left list
- leftListData = listBoxesWithTransferableItems.getAllItemsFromLeftListBox();
- assertTrue(Arrays.equals(LIST_DATA_LEFT, leftListData));
-
- // there was nothing selected in left list, so nothing should be added to right list
- rightListData = listBoxesWithTransferableItems.getAllItemsFromRightListBox();
- assertTrue(Arrays.equals(LIST_DATA_RIGHT, rightListData));
-
- listBoxesWithTransferableItems.selectItemInLeftListAtIndex(0);
- leftToRightTransferButton.doClick();
-
- assertEquals("Items in left list should have decreased by 1",
- LIST_DATA_LEFT.length - 1, listBoxesWithTransferableItems.getAllItemsFromLeftListBox().length);
- assertEquals("Items in left list should have increased by 1",
- LIST_DATA_RIGHT.length + 1, listBoxesWithTransferableItems.getAllItemsFromRightListBox().length);
-
- }
and here's the source code for the transfer from left-to-right!!!
- private void transferSelectedItemFromLeftListBoxToRight() {
- int selectedIndex = getSelectedIndexOfLeftListBox();
-
- // return if no selected item
- if (selectedIndex == -1) return;
-
- Object selectedItemFromLeftListBox = getSelectedItemFromLeftListBox();
-
- // remove selected item from left list
- DefaultListModel leftListModel = (DefaultListModel) leftListBox.getModel();
- leftListModel.removeElement(selectedItemFromLeftListBox);
-
- // add removed item from left list to right list
- DefaultListModel rightListModel = (DefaultListModel) rightListBox.getModel();
- rightListModel.addElement(selectedItemFromLeftListBox);
- }
Miscellaneous - GUITestHelper Class
The GUITestHelper
provides utility methods to find Swing components contained in a container. The components can be searched for using some conditions such as their text contents (JLabel
) or field length (JTextField
). One could expand this utility to find other GUI components such as JButtons
, JMenuItems
, etc. The code for GUITestHelper
is shown below.
- /*
- * Class with static helper methods for GUI testing.
- *
- * Author: Santosh Shanbhag
- */
- package com.ociweb.testinggui;
-
- import javax.swing.*;
- import java.awt.*;
-
- public class GUITestHelper {
-
- /**
- * Find out if the container and its sub-containers contain a JLabel with the specified
- * text.
- * @param container
- * @param labelText
- * @return JLabel with the specified text, if found. Otherwise, return null.
- */
- public static JLabel findJLabelContainingText(Container container, String labelText) {
- Component[] components = container.getComponents();
- JLabel labelToFind = null;
-
- for (int i = 0; i < components.length; i++) {
- Component component = components[i];
-
- // if the component is a container, find out if it contains the JLabel
- if (component instanceof Container) {
- // recursion!!!
- labelToFind = findJLabelContainingText((Container) component, labelText);
- if (labelToFind != null) break;
- }
-
- // if the component is a JLabel, find out if it contains the text
- if (component instanceof JLabel) {
- JLabel label = (JLabel) component;
- // compare the label text with the text passed in
- if (label.getText().equals(labelText)) {
- labelToFind = label;
- break;
- }
- }
- }
- return labelToFind;
- }
-
- /**
- * Find out if the container and its sub-containers contain a JTextField of the specified length
- * @param container
- * @param fieldLength
- * @return JTextField having the specified length, if found. Otherwise, return null.
- */
- public static JTextField findJTextFieldOfLength(Container container, int fieldLength) {
- Component[] components = container.getComponents();
- JTextField textFieldToFind = null;
- for (int i = 0; i < components.length; i++) {
- Component component = components[i];
-
- // if the component is a container, find out if it contains the JTextField
- if (component instanceof Container) {
-
- // recursion!!!
- textFieldToFind = findJTextFieldOfLength((Container) component, fieldLength);
- if (textFieldToFind != null) break;
- }
-
- // if the component is a JTextField, find out if it is of the specified length
- if (component instanceof JTextField) {
- JTextField textField = (JTextField) component;
-
- // compare the length of text field with that passed in
- if (textField.getColumns() == fieldLength) {
- textFieldToFind = textField;
- break;
- }
- }
- }
- return textFieldToFind;
- }
-
-
- /**
- * Find out if the container and it's sub-containers contain a JButton having the specified text.
- *
- * @param container
- * @param buttonText
- * @return JButton containing the text, if found. Otherwise, return null.
- */
- public static JButton findButtonWithText(Container container, String buttonText) {
- Component[] components = container.getComponents();
-
- JButton buttonToFind = null;
- for (int i = 0; i < components.length; i++) {
- Component component = components[i];
-
- // if the component is a container, find out if it contains the JButton
- if (component instanceof Container) {
- buttonToFind = findButtonWithText((Container) component, buttonText);
- if (buttonToFind != null) break;
- }
-
- // if the component is a JButton, find out if it contains the text
- if (component instanceof JButton) {
- JButton button = (JButton) component;
- // compare the length of text field with that passed in
- if ( button.getText().equals(buttonText) ) {
- buttonToFind = button;
- break;
- }
- }
- }
- return buttonToFind;
- }
-
- }
Summary
Java Swing provides a framework of sophisticated components. Testing Swing applications is challenging but not overly complicated. Indeed there are many GUI testing frameworks available that ease the process of GUI testing. This article demonstrated using the test driven approach to developing custom GUI components using Swing and JUnit. A GUI test helper class provides useful methods to find components without the need to expose them using accessors in the original class.
References
- [1] JUnit Home Page
http://www.junit.org - [2] Java Foundation Classes (JFC/Swing)
http://java.sun.com/products/jfc/index.jsp - [3] Creating a GUI with JFC/Swing
http://java.sun.com/docs/books/tutorial/uiswing/ - [4] Abbot: Java GUI Test Framework
http://abbot.sourceforge.net