Reputation: 367
I would like to write test cases for a GUI. I want to know how do you simulate a click of JButton, or how do you extract the elements of a JTable.
For the purpose of this, I have built a simple GUI that increase the count by 1 if the button is clicked and the JTextfield is empty, but the count is replaced by the integer in the JTextfield if a number is provided. Of course I would like to use Regex to make sure the text entered into the JTextfield is actually an integer, but let's assume users won't mess around and enter a non-integer. In addition, the JLabel updates the current count while the JTable adds a new row.
Here's the code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class sampleGUI extends JFrame implements ActionListener {
private Integer previous_count;
private Integer current_count;
private JButton Button;
private JTable table;
private JTextField text;
private DefaultTableModel model;
private JScrollPane scroll;
private JLabel label;
public sampleGUI() {
previous_count = null;
current_count = 0;
JFrame frame = new JFrame("Sample");
JPanel panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
label = new JLabel("Current Count: " + Integer.toString(current_count));
text = new JTextField(15);
Button = new JButton("Change the Count!");
model = new DefaultTableModel();
model.addColumn("Previous Count");
model.addColumn("Current Count");
table = new JTable(model);
scroll = new JScrollPane(table);
layout.setHorizontalGroup(layout
.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(
layout.createSequentialGroup().addComponent(label)
.addComponent(text).addComponent(Button))
.addComponent(scroll));
layout.setVerticalGroup(layout
.createSequentialGroup()
.addGroup(
layout.createParallelGroup(
GroupLayout.Alignment.BASELINE)
.addComponent(label).addComponent(text)
.addComponent(Button)).addComponent(scroll));
Button.addActionListener(this);
frame.add(panel);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Button) {
if (text.getText().equals("")) {
previous_count = current_count;
current_count++;
label.setText("Current Count: "
+ Integer.toString(current_count));
model.addRow(new Object[] { current_count, previous_count });
} else {
previous_count = current_count;
current_count = Integer.parseInt(text.getText());
label.setText("Current Count: "
+ Integer.toString(current_count));
text.setText("");
model.addRow(new Object[] { current_count, previous_count });
}
table.changeSelection(table.getRowCount() - 1, 0, false,
false);
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
sampleGUI gui = new sampleGUI();
}
});
}
}
Let's say I would like to simulate opening the GUI, then click the button once without entering any text, then enter 1234 and click the button, then click the button without entering any text, the JTable should have 3 columns: {{1,0}, {1234, 1}, {1235, 1234}}. How can I write the test for that? Thanks!
Upvotes: 31
Views: 52808
Reputation: 5819
You can probably use JAuto and xdotool to achieve that kind of automation under Linux X11. Without seeing your source code, JAuto can dump AWT/Swing UI component class names and coordinates. You use this information to decide what to enter into a text field and where to click. Then use xdotool to simulate mouse and keyboard.
The two tools are not written for testing purposes per se, you can still rig up a mechanism for your program to write a file or display something on screen for confirming a test success.
Disclaimer: I'm the author of JAuto.
Upvotes: 2
Reputation: 119
normally you have to keep in mind what you want to test in your application.lets say you want to test the components in the application so as to check whether any changes has taken place in the future that affect the current format.and second to check the logic or method provided in the swing application ie,whether any change in the flow will effect the return statements.
lets consider this implementation method
public void activate()
{
f=new JPanel();
tf=new JTextField();
tf.setBounds(50,50, 150,20);
tf.setName("b1");
b=new JButton("Click Here");
b.setName("Click Here");
b.setBounds(50,100,95,30);
f.add(b);
f.add(tf);
f.setSize(400,400);
f.setLayout(null);
f.setVisible(true);
//b.doClick();
}
@Test
public void testActivate()
{
btn=new Button();
assertNotNull(btn);
JPanel jf=btn.f;
btn.activate();
int height=b.getHeight();
int width=b.getWidth();
assertEquals(30,height);
assertEquals(95,width);
int x=b.getX();
int y=b.getY();
assertEquals(50,x);
assertEquals(100,y);
int x1=tf.getX();
int y1=tf.getY();
assertEquals(50,x1);
assertEquals(50,y1);
}
further if you want to stimulate button click you can use doClick method of that object instance
btn.run();
b.doClick();
String str=tf1.getText().toString();
assertEquals("Welcome to junit.",str);
Upvotes: 0
Reputation: 436
AssertJ is a fork of FEST that is working very well for me, and has support for Swing. Development is active (at time of writing), supports Java 8, has assertions for a few popular libraries such as Guava and Joda Time, and is very well documented. It is also free and open.
Upvotes: 6
Reputation: 13499
I had a project a few years back where we needed to automate tests.
We ended up going with :
jfcunit
We also tried out
fest - was good but at the time of writing was only single threaded.
swingunit - also ok, but we had a few subtle problems so we needed to ditch it
Upvotes: 4
Reputation: 1306
Generally a good practice is to design your view layer as thin as possible so you don't have to test it and you focus on a business logic. In order to achive that people are using design patterns like Model View Presenter or Presentation Model.
But if you have to test GUI then you can try windowlicker: - https://code.google.com/p/windowlicker/
Upvotes: 0
Reputation:
Java SE comes with a standard tool for doing just this, the Robot class. I've only ever used it to write bots for games and to remotely control a separate computer via a socket server/client pair, but it was actually intended to automate testing, and so it should work for you. The basic format is simple:
Robot bot = new Robot();
bot.mouseMove(10,10);
bot.mousePress(InputEvent.BUTTON1_MASK);
//add time between press and release or the input event system may
//not think it is a click
try{Thread.sleep(250);}catch(InterruptedException e){}
bot.mouseRelease(InputEvent.BUTTON1_MASK);
Of course you can simulate keyboard events in a similiar way as well using the appropriate keyPress/keyRelease methods. I've sometimes found it useful to use the screenCapture method of the robot class as well to seach for images on the screen and determine where to click.
Note: this does not require that the windows you are testing are built on awt/swing, however it does require that the java implementaton you are using supports awt.
Upvotes: 23