Создадим простое Swing приложение, как показано на рисунке:
Для создания Swing приложений нужно подключить соответствующие библиотеки:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Далее в конструкторе SwingApplication() :
1. Создадим объект JFrame:
JFrame myFrame = new JFrame("Button Label Text");
2. Установим для него разметку в виде таблицы GridLayout:
myFrame.setLayout(new GridLayout(0,2,5,5));
где 0 - любое число строк, 2 - число столбцов , 5 зазоры по вертикали и по горизонтали.
3. Расположим компоненты на JFrame:
JLabel myLabel = new JLabel("");
myFrame.add(myLabel);
JTextField myTextField = new JTextField(20);
myFrame.add(myTextField);
JButton myBut = new JButton("First");
myFrame.add(myBut);
4. Добавим обработку действий (событий) таким компонентам, как JTextField и JButton:
SwingApplication(){
...
myTextField.setActionCommand("field1");
myTextField.addActionListener(this);
myBut.addActionListener(this);
...
}//Окончание конструктора
/**Добавляем метод обрабатывающий события кликов, ввода текста и т.д.
*/
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("First")){
myTextField.setText("First pressed");
}
else if(e.getActionCommand().equals("field1")){
myLabel.setText(myTextField.getText());
}
}
В класе SwingApplication создадим публичный метод, который стартует данное приложение startApp() :
/**
* Method for starting SwingApplication
*/
public static void startApp(){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new SwingApplication();
}
});
}
Полный код приложения SwingApplication.java.
Для запуска приложения из командной строки, проверяем переменную CLASSPATH:
# env|grep CLASSPATH
CLASSPATH=./:/home/JavaClasses:/home/JavaClasses/jemmy-2.2.7.5.jar:/home/JavaClasses/junit4-4.5.jar
Заметьте jemmy-2.2.7.5.jar и junit4-4.5.jar нам будут нужны для запуска тестов, не забудьте их тоже прописать.
Теперь копируем класс ( с пакетом) в эту папку и компилируем
# javac /home/JavaClasses/swing/SwingApplication.java
Запускаем для проверки откомпилированный java-code
# java swing.SwingApplication
Jemmy позволяет искать компоненты на фрейме ( диалоге), создавать события такие как,
а также считывать значения из компонентов, таких как Text, Title и т.д.
Компоненты можно искать с помощью методов:
Чем больше параметров Вы знаете о компоненте, тем проще Вам его будет потом найти.
А именно, можно найти JButton следующими способами:
Для использования возможностей Jemmy, необходимо сначала подключить нужные библиотеки:
import org.netbeans.jemmy.*;
import org.netbeans.jemmy.operators.*;
Как следует из названия, каждый тест должен быть потомком класса Scenario. Удобнее всего создавать тесты в каком-нибудь IDE.
Создадим пакет test_scenario и создадим в нем Java class. Сделаем его наследником класса Scenario:
package test_scenario;
import swing.*;
import org.netbeans.jemmy.*;
import org.netbeans.jemmy.operators.*;
/**Testing class by Jemmy 2 toolkit
*
* @author Shpatserman Maria
*/
public class SwingApplicationScenario implements Scenario{
}
Этот класс должен переопределять метод родительского класса runIt() . Внутри этого метода мы опишем тест, реализующий поиск всех нужных компонентов, нажатие кнопок, ввод текста и т.д. Получим метод следующего вида:
public int runIt(Object param) { try { //Запуск Swing приложения new ClassReference("swing.SwingApplication").startApplication(); //Поиск JFrame JFrameOperator mainFrame = new JFrameOperator("SwingApplication"); //Делаем небольшую задержку new QueueTool().waitEmpty(200); //Ищем кнопку по имени JButtonOperator firstButton = new JButtonOperator(mainFrame, "First"); firstButton.push(); //Ищем JTextField по имени после нажатия кнопки должно стать "First pressed" JTextFieldOperator textField = new JTextFieldOperator(mainFrame,"First pressed"); //Очищаем поле ввода textField.clearText(); textField.enterText("Hello"); //После ввода текста на JFrame должен появиться JLabel //Метка должна быть "Hello" new JLabelOperator(mainFrame,"Hello"); //Поиск второго компонента JTextField по индексу JTextFieldOperator textField2 = new JTextFieldOperator(mainFrame,1); textField2.enterText("Field2"); //Опять ищем JLabel по тексту new JLabelOperator(mainFrame,"Field2"); JButtonOperator secondButton = new JButtonOperator(mainFrame, "Second"); secondButton.push(); mainFrame.close(); } catch(Exception e) { e.printStackTrace(); return(1); } return(0); }
Для запуска теста делаем класс исполняемым. Создаем метод main:
public static void main(String [] argv){ String[] params = {"test_scenario.SwingApplicationScenario"}; org.netbeans.jemmy.Test.main(params); }
Полный код класса SwingApplicationScenario.java
Компилируем класс:
Запускаем тест из командной строки:
Наименование окон кнопок и других компонентов можно задавать не только напрямую в тексте программы, но и считывать значения из файла. Для этого используем объект класса Bundle и его метод getResource():
...
Bundle bundle = new Bundle();
bundle.loadFromFile("/home/java/properties_for_test");
//wait frame
JFrameOperator mainFrame = new JFrameOperator(bundle.getResource("main_window"));
...
Пример файла с заданными параметрами: properties_for_test.
Класс использующий передачу параметров из файла: ScenarioByFile.java.
С помощью Unit-тестов нужно обязательно тестировать внешние (public) методы, а также API.
В нашем случае мы напишем Unit-тесты для тестирования GUI.
Теперь обернем все пункты из сценариев в небольшие, независимые тесты. Чем меньше будет Unit-тест, тем проще
его будет отлаживать. Название каждого Unit-теста сделаем подробным и читаемым. Не скупитесь на комментарии.
Основные ключевые слова(обозначения) в Unit-тестах следующие:
Методы обозначенные как @Before/@After должны быть public. Методы обозначенные как @BeforeClass/@AfterClass должны быть public static. В блок @Before завернем создание тестового приложения:
@Before public void getFrame(){ //Создаем приложение SwingApplication.startApp(); //Ищем фрейм mainFrame=new JFrameOperator(); //Это приостановление очереди выполнения событий //просто для того, чтобы было удобнее смотреть mainQueue = new QueueTool(); mainQueue.waitEmpty(200); }
В блок @BeforeClass обернем временные настройки - ожидание окна, ожидание компонентов и т.д. Если за указанные промежутки времени компоненты не будут найдены, то тест будет провален.
@BeforeClass public static void setTimeouts(){ //Скорость набора символов JemmyProperties.setCurrentTimeout("JTextComponentOperator.PushKeyTimeout", 50); //Максимальное время ожидания JFrame JemmyProperties.setCurrentTimeout("FrameWaiter.WaitFrameTimeout", 2000); //Максимальное время ожидания всех компонентов JemmyProperties.setCurrentTimeout("ComponentOperator.WaitComponentTimeout", 1000); }
Теперь напишем простой тест, определяющий корректность названия нашего окна JFrame:
@Test public void testTitleFrame(){ //У найденного ранее фрейма берем параметр Имя окна String titleFrame = mainFrame.getTitle(); //Сравниваем с ожидаемым значением assertEquals("Button Label Text",titleFrame); mainQueue.waitEmpty(100); }
Каждый Unit-тест должен иметь утверждающие методы, такие как:
И многие другие.
Аналогично обернем в тест нажатие кнопок и проверку корректности значений в полях. Как было видно из п.4 ( разработки Swing приложения)
при нажатии на кнопку First в поле myTextField должен был появиться текст "First pressed".
Это мы и будем использовать, как проверочное условие.
@Test public void testActionButtons(){ //Теперь находим кнопку по её имени First JButtonOperator butn1 = new JButtonOperator(mainFrame,"First"); //Осуществляем клик butn1.push(); JTextFieldOperator LeftField = new JTextFieldOperator(mainFrame,0); //Сравниваем значение поля с ожидаемым assertTrue("After First Button push LeftField should " + "contained \"First pressed\" string",LeftField.getText().equals("First pressed")); mainQueue.waitEmpty(500); JButtonOperator butn2 = new JButtonOperator(mainFrame,"Second"); butn2.push(); JTextFieldOperator RightField = new JTextFieldOperator(mainFrame,1); //Делаем проверку на НЕ совпадение значений assertFalse("After Second Button push RightField should " + "not contain \"AAA\" string ",RightField.getText().equals("AAA")); mainQueue.waitEmpty(500); }
Добавим аналогичный тест для проверки реакции на ввод текста в поля и обновления JLabel. А также тест, который смотрит все ли компоненты присутствуют.
Полный исходный код тестового класса TestSwingApplication.java
Запускаем тестовый класс в IDE Netbeans 6.5:
Компилируем тест( должен лежать в той же папке что и тестируемое приложение):
# javac /home/JavaClasses/swing/TestSwingApplication.java
Запускаем:
# java org.junit.runner.JUnitCore swing.TestSwingApplication
Результат:
Замечание: В новой версии JUnit 4 Вам не надо делать тестовые классы наследниками Test Case, как было в версии JUnit 3.
Исходный код проекта Swing с использованием Jemmy ver.2 для тестирования GUI : SwingUnitJemmyTests.tar.gz.
jar файл классов для выполнения примеров: Swing_UnitTests.jar.
Тестовый файл настроек: properties_for_test.
Более подробно о Jemmy Toolkit можно прочитать здесь.