To test a GUI, we first need to find the components we want to perform user input simulation on or state verification. This section explains how to find GUI components in AssertJ Swing.
To simulate user input on a GUI, AssertJ Swing first needs to find the GUI component(s) that will participate in the test. For example, to simulate a user pressing a ok button, AssertJ Swing first needs to find that button. AssertJ Swing provides different ways to lookup a GUI component:
Using a unique name for GUI components guarantees that we can always find them, regardless of any change in
the GUI (as long as the components have not been removed). For example, to find a button having the name
ok
, we need to set that name in the button before we execute our tests:
JButton okButton = new JButton("OK");
okButton.setName("ok");
Finding components by type is reliable as long as the GUI under test has only one component of such type.
There are times when the GUI under test does not provide unique names for their components (e.g. legacy
applications). To overcome this limitation, AssertJ Swing provides a way to specify custom search
criteria using a GenericTypeMatcher
. In this example we create a GenericTypeMatcher
that matches a JButton
containing the text OK
:
GenericTypeMatcher<JButton> textMatcher = new GenericTypeMatcher<JButton>(JButton.class) {
@Override protected boolean isMatching(JButton button) {
return "OK".equals(button.getText());
}
};
GenericTypeMatcher
guarantees that the component passed as argument in the method
isMatching(Component)
is never null
.
By default, AssertJ Swing supports looking up components by name, type and
custom search criteria. To specify
custom search criteria, users need to provide an implementation of GenericTypeMatcher
or
ComponentMatcher
.
AssertJ Swing provides some common-use component matchers in the package
org.assertj.swing.core.matcher
:
DialogMatcher
Dialog
containing the specified name, title or visibilityFrameMatcher
Frame
containing the specified name, title or visibilityJButtonMatcher
JButton
containing the specified name, title or visibilityJLabelMatcher
JLabel
containing the specified name, title or visibilityJTextComponentMatcher
JTextComponent
containing the specified name, title or visibilityThe following example shows how to find and click a JButton
with name ok
and text
Ok
, in a JFrame
using a JButtonMatcher
:
// import static org.assertj.swing.core.matcher.JButtonMatcher.withText;
FrameFixture window = new FrameFixture(robot(), frame);
window.show();
window.button(withName("ok").andText("OK")).click();
Regardless of the lookup type, AssertJ Swing provides two ways to perform GUI component lookup
ContainerFixture
The abstract class
ContainerFixture
provides shortcuts to look up GUI components inside the Container
being tested. There are three
overloaded versions of each shortcut method, one for each component lookup type (by name, type or
GenericTypeMatcher
).
The following example uses a FrameFixture
, a concrete implementation of
ContainerFixture
, to look up a login JButton
by name, type and custom
search criteria:
// by name
JButtonFixture button = window.button("login");
// by type
JButtonFixture button = window.button();
// custom search criteria (the button's text)
JButtonFixture button = window.button(new GenericTypeMatcher<JButton>(JButton.class) {
@Override
protected boolean isMatching(JButton button) {
return "Login".equals(button.getText());
}
});
By default, only components that are showing on the screen can participate in component lookups (except for
JMenuItem
, which are not showing until they are selected). To change the scope of component
lookups, simply call the method componentLookupScope(ComponentLookupScope)
in
Settings
. All instances of Robot
contain their own Settings
,
which is returned by the method settings()
. For more information about component lookup
scope, please read ComponentLookupScope
's
documentation.
// including showing and not-showing components in component lookups
Robot robot = BasicRobot.robotWithNewAwtHierarchy();
robot.settings().componentLookupScope(ComponentLookupScope.ALL);
GenericTypeMatcher
need to specify if lookup includes non-showing
components or not.
ComponentFinder
Although we recommend to look up GUI components using a ContainerFixture
, you can also use a
ComponentFinder
. It supports different types of component lookup (please find details in
its documentation):
ComponentMatcher
GenericTypeMatcher
There are three ways to obtain a ComponentFinder:
ComponentFinder
that has access to all the GUI components in the AWT
hierarchy.
ComponentFinder finder = BasicComponentFinder.finderWithCurrentAwtHierarchy();
ComponentFinder
that only has access to the GUI components created after
it. In the following example, finder has access to MainFrame
but not to LoginFrame
.
// new LoginFrame();
ComponentFinder finder = BasicComponentFinder.finderWithNewAwtHierarchy();
finder.findByName("login", true); // will fail finding component of login frame
// new MainFrame();
finder.findByName("pw", true); // will work finding label of main frame
ComponentFinder
from a Robot
. In the following
example we're going to use the Robot
from the
base test class:
ComponentFinder finder = robot().finder();
AssertJ Swing provides support for finding GUI components after the execution of a long-duration task
is complete. Currently, it provides the following finders (in the package
org.assertj.swing.finder
):
WindowFinder
(which can find instances of Frame and Dialog)JOptionPaneFinder
JFileChooserFinder
A good example for a long running task is the login procedure of an application. The main window is being shown after the user's credentials have been successfully verified. The following are the typical steps to complete such scenario:
The tricky part here is step 4. Authentication/authorization can take some time (depending on network traffic, etc.) and we need to wait for the main window to appear in order to continue our test. It is possible to test this scenario with AssertJ Swing:
// import static org.assertj.swing.finder.WindowFinder.findFrame;
window.textBox("username").enterText("yvonne");
window.textBox("password").enterText("welcome");
window.button("login").click();
// now the interesting part, we need to wait till the main window is shown.
FrameFixture mainFrame = findFrame("main").using(robot());
// we can continue testing the main window.
The findFrame()
method (statically imported from WindowFinder
) can look up a
Frame having main
as its name with a default timeout of 5 seconds. This means that if in
5 seconds the frame we're looking for isn't found, the test will fail.
We can also specify a custom value for the timeout. For example, we can set the timeout to 10 seconds in two ways:
// import static org.assertj.swing.finder.WindowFinder.findFrame;
// import static java.util.concurrent.TimeUnit.SECONDS;
FrameFixture mainFrame = findFrame("main").withTimeout(10000).using(robot());
// or
FrameFixture mainFrame = findFrame("main").withTimeout(10, SECONDS).using(robot());
We can also find components by type. In this example, we look up a showing a Frame
of type
MainFrame
, using the default timeout of 5 seconds.
// import static org.assertj.swing.finder.WindowFinder.findFrame;
FrameFixture mainFrame = findFrame(MainFrame.class).using(robot());
All finders accept a GenericTypeMatcher
to find components using custom search criteria. In
the following example, we look up a showing frame whose title starts with News
:
// import static org.assertj.swing.finder.WindowFinder.findFrame;
GenericTypeMatcher<JFrame> matcher = new GenericTypeMatcher<JFrame>(JFrame.class) {
protected boolean isMatching(JFrame frame) {
return frame.getTitle() != null && frame.getTitle().startsWith("News") && frame.isShowing();
}
};
FrameFixture frame = findFrame(matcher).using(robot());
In the example above, we used the method call using(loginDialog.robot)
. Although strange,
this is necessary because, in a given test, only one instance of Robot
can be running, to
prevent GUI tests from blocking each other on the screen. In other words, in a test class you can only use
one and only one instance of Robot.