-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathassertj-swing-advanced.html
352 lines (294 loc) · 20 KB
/
assertj-swing-advanced.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="AssertJ site">
<meta name="author" content="Joel Costigliola">
<title>AssertJ / Fluent assertions for java</title>
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Inconsolata|Source+Code+Pro|Open+Sans|Ubuntu|Varela+Round|Karla">
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="font-awesome/css/font-awesome.min.css" rel="stylesheet">
<script src="highlight/highlight.pack.js"></script>
<link rel="stylesheet" href="highlight/styles/railscasts.css">
<script>hljs.initHighlightingOnLoad();</script>
<link href="css/assertj.min.css" rel="stylesheet">
<link rel="shortcut icon" href="favicon.png" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- You'll want to use a responsive image option so this logo looks good on devices - I recommend using something like retina.js (do a quick Google search for it and you'll find it) -->
<a class="navbar-brand" href="index.html">AssertJ</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="assertj-core-quick-start.html">Quick start</a></li>
<li><a href="assertj-news.html">News</a></li>
<li><a href="assertj-core.html">Core</a></li>
<li><a href="assertj-assertions-generator.html">Assertions generator</a></li>
<li><a href="assertj-guava.html">Guava</a></li>
<li><a href="assertj-joda-time.html">Joda-Time</a></li>
<li><a href="assertj-db.html">DB</a></li>
<li><a href="assertj-neo4j.html">Neo4j</a></li>
<li><a href="assertj-swing.html">Swing</a></li>
<li><a href="assertj-help.html">Help</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row" >
<div class="col-md-2 assertj-sidebar-menu">
<div class="bs-sidebar hidden-print affix-top" role="complementary">
<ul class="bs-sidenav nav ">
<li class="sidenav-header">About</li>
<li><a href="assertj-swing.html">Overview</a></li>
<li><a href="assertj-swing-quick-start.html">Quick start</a></li>
<li><a href="assertj-swing-news.html">News & releases</a></li>
<li><a href="swing/api/index.html">Javadoc</a></li>
<li><a href="assertj-swing.html#code">Code & issues <i class="fa fa-github"></i></a></li>
<li><a href="assertj-swing.html#contributing">Contributing</a></li>
<li class="sidenav-header">Working with it</li>
<li><a href="assertj-swing-getting-started.html">Getting started</a></li>
<li><a href="assertj-swing-basics.html">Basics</a></li>
<li><a href="assertj-swing-edt.html">EDT</a></li>
<li><a href="assertj-swing-lookup.html">Component lookup</a></li>
<li><a href="assertj-swing-launch.html">Launching</a></li>
<li><a href="assertj-swing-input.html">Input simulation</a></li>
<li><a href="assertj-swing-running.html">Running tests</a></li>
<li><a href="assertj-swing-troubleshooting.html">Troubleshooting</a></li>
<li><a href="assertj-swing-advanced.html">Advanced features</a></li>
<li class="sidenav-header">Migrating</li>
<li><a href="assertj-swing-migrating.html">From Fest</a></li>
</ul>
</div>
</div>
<div class="col-lg-10 col-md-10 col-sm-10 text-left" >
<h1 class="page-header">Advanced Features</h1>
<h2>Assertions with Timeouts</h2>
<p>Sometimes it is necessary to have a timeout when verifying that a particular condition has been satisfied
or the application has reached a particular state. For example, some UI tests may involve asynchronous
operations or time-consuming tasks.</p>
<p>The following code listing shows how to perform assertions using timeouts. In our example, we are going to
assume that a <code>JButton</code> is enabled after calling a web service asynchronously. In our example,
if the <code>JButton</code> is not enabled after 10 seconds, the test will fail. The exception thrown
will include the description of the <code>Condition</code>.</p>
<pre class="pre-scrollable"><code class="language-java">// import static org.assertj.swing.timing.Pause.pause;
// import static org.assertj.swing.timing.Timeout.timeout;
// import static org.assertj.swing.edt.GuiActionRunner.execute;
final JButton okButton = //obtain a reference to the "OK" button
pause(new Condition("OK button to be enabled") {
public boolean test() {
return execute(okButton::isEnabled);
}
}, timeout(10000));</code></pre>
<h2>Component Formatters</h2>
<p>A component formatter is an implementation of the interface <code>ComponentFormatter</code> that creates a
<code>String</code> representation of a GUI component. AssertJ Swing provides default component
formatters for all the Swing components in the JDK. Unlike the <code>toString()</code> method in Swing
components, the provided component formatters display only the information that can help developers solve
problems in functional tests, excluding any information related to the appearance of GUI components
(e.g. colors, layouts, sizes, etc.). Here are some examples:</p>
<pre><code>org.assertj.swing.test.TestFrame[name='frame', title='FormattingTest', enabled=true, showing=true]
javax.swing.JButton[name='button', text='A button', enabled=false]
javax.swing.JList[name='list', selectedValues=['One', 2], contents=['One', 2, 'Three', 4], selectionMode=MULTIPLE_INTERVAL_SELECTION, enabled=true]
javax.swing.JOptionPane[message='A message', messageType=ERROR_MESSAGE, optionType=DEFAULT_OPTION, enabled=true, showing=false]
javax.swing.JTabbedPane[name='tabbedPane', selectedTabIndex=1, selectedTabTitle='Second', tabCount=2, tabTitles=['First', 'Second'], enabled=true]:</code></pre>
<h3>Custom Component Formatters</h3>
<p>There might be cases that you might want to create your own custom formatter to override an existing one or
to add support for custom GUI components.</p>
<h4>Implement the ComponentFormatter interface</h4>
<p>The interface <code>ComponentFormatter</code> provides two methods:</p>
<ul>
<li><code>Class<? extends Component> targetType()</code> returns the type of component this formatter
supports. For example, by returning <code>JButton.class</code> a formatter indicates that it supports
instances of <code>JButton</code> and its subclasses.</li>
<li><code>String format(Component c)</code> returns the <code>String</code> representation of the given GUI
component.</li>
</ul>
<h4>Configure an IntrospectionComponentFormatter</h4>
<p>The easiest way to create a component formatter is to configure an instance of
<code>IntrospectionComponentFormatter</code>, which, as the name suggests, uses introspection to display
property values of a GUI component. The following code listing shows how to configure a
<code>IntrospectionComponentFormatter</code> to support <code>JLabel</code> (and subclasses) and the
properties to show:</p>
<pre><code class="language-java">IntrospectionComponentFormatter formatter =
new IntrospectionComponentFormatter(JLabel.class, "name", "text", "enabled");</code></pre>
<h4>Register your custom formatter</h4>
<p>After creating a custom formatter, we need to register it with AssertJ Swing. It is very simple, we
only need to call the static method <code>register</code> in
<code>org.assertj.swing.format.Formatting</code>.</p>
<pre><code class="language-java">Formatting.register(new MyFormatter());</code></pre>
<div class="panel panel-info">
<div class="panel-heading">Note</div>
<div class="panel-body">
AssertJ Swing uses the formatter that supports the type that is the closest to the type of the given
GUI component. For example, if we have <code>formatter1</code>, a formatter registered to format instances of
<code>JButton</code>, and <code>formatter2</code>, a formatter registered to format instances of
<code>MyOwnButton</code> (a subclass of <code>JButton</code>), AssertJ Swing will use
<code>formatter2</code> to format instances of <code>MyOwnButton</code>.
</div>
</div>
<h2>Extending AssertJ Swing</h2>
<p>It is very likely that, in your application, you are using <em>custom</em> Swing components (e.g. Flamingo,
JIDE, or your own). Since AssertJ Swing currently supports only the <em>standard</em> Swing components
(the ones that come in the JDK), you might want to create your own AssertJ Swing fixtures to test
your application.</p>
<p>The following are some suggestions or recommendations you can follow when creating your own
AssertJ Swing fixture:</p>
<h3>Take a look at the code and Javadocs of existing AssertJ Swing fixtures</h3>
<p>By reading AssertJ Swing's code you can learn to use the <code>BasicRobot</code> to simulate a user
moving the mouse, clicking a mouse button or pressing keyboard keys. We have separated the structure of a
component fixture in several layers (from bottom to top):</p>
<ol>
<li><code>BasicRobot</code>. Simulates a user interacting with a mouse and keyboard. It uses the AWT Robot to
generate native input events.</li>
<li>Component driver. This layer does all the <em>heavy lifting</em>. All interaction with a GUI component is
done in this layer. It knows how to simulate events and check the state of a specific GUI component.
For example, <code>JComboBoxDriver</code> knows how to simulate a user using a <code>JComboBox</code>
(selecting a particular element) and how to verify the state of it (which element should be
selected).</li>
<li>Component fixture. This layer sits on top of the driver. It provides a fluent interface to that makes
the API easier to write and read. Users of AssertJ Swing write their GUI tests using fixtures,
not drivers. Fixtures can be considered the <em>user interface</em> of the AssertJ Swing
library.</li>
</ol>
<h3>Extend an existing AssertJ Swing fixture</h3>
<p>If the component you want to test is a subclass of a JDK Swing component (e.g. you have a custom button that
extends <code>JButton</code>), you can extend an existing concrete AssertJ Swing fixture
(<code>JButtonFixture</code> in our example).</p>
<p>If the custom GUI component does not extend any JDK Swing component, or if you prefer to create a
AssertJ Swing fixture from scratch, please read the following</p>
<ul>
<li>Extend <a href="swing/api/org/assertj/swing/fixture/AbstractComponentFixture.html" target="_blank">AbstractComponentFixture</a>.
This class provides all the necessary wiring of a GUI component to test and a <code>Robot</code>. It also
provides some very basic functionality and convenience methods.</li>
<li>If want to simulate a user right-clicking on your component and showing a <code>JPopupMenu</code>,
extend <a href="swing/api/org/assertj/swing/fixture/AbstractJPopupMenuInvokerFixture.html" target="_blank">AbstractJPopupMenuInvokerFixture</a>.</li>
</ul>
<div class="panel panel-danger">
<div class="panel-heading">Warning</div>
<div class="panel-body">
To avoid unexpected side effects in your tests, you must access Swing components in the event dispatch thread.
</div>
</div>
<h3>Create an extension for AbstractContainerFixture</h3>
<p>By default, implementations of <a href="swing/api/org/assertj/swing/fixture/AbstractContainerFixture.html" target="_blank">AbstractContainerFixture</a>
provide shortcut methods to access the standard Swing components (the ones that come in the JDK) in a Container. For example, the following code listing
shows shortcuts methods to access a <code>JLabel</code> and a <code>JTree</code> from a <code>JFrame</code> being managed by a <code>FrameFixture</code>:</p>
<pre><code class="language-java">FrameFixture frame = new FrameFixture(new MyFrame());
frame.label("pathLabel").requireText("Path:");
frame.tree("navigationTree").selectPath("c:/projects/fest");</code></pre>
<p>If you have created a fixture for your custom GUI component, it is not possible to add a shortcut to
<code>AbstractContainerFixture</code> due to the lack of extension methods in Java. For example, let's assume you have
created a custom GUI component called <code>MyCalendar</code> and a fixture to use this custom component in
your GUI tests called <code>MyCalendarFixture</code>. It is not possible to add the shortcut method calendar
to <code>AbstractContainerFixture</code> and have all its implementations look like this:</p>
<pre><code class="language-java">frame.calendar("myCalendar").selectDate("10/18/08");</code></pre>
<p>To overcome this limitation, AssertJ Swing provides <a href="swing/api/org/assertj/swing/fixture/ComponentFixtureExtension.html" target="_blank">ComponentFixtureExtension</a>.
The following code listing shows an extension to add a shortcut to a <code>MyCalendarFixture</code>. This extension looks up a
<code>MyCalendar</code> that has a matching name and is showing on the screen:</p>
<pre class="pre-scrollable"><code class="language-java">public class MyCalendarFixtureExtension extends ComponentFixtureExtension<MyCalendar, MyCalendarFixture> {
public static MyCalendarFixtureExtension calendarWithName(String name) {
return new MyCalendarFixtureExtension(name);
}
private final String name;
private MyCalendarFixtureExtension(String name) {
this.name = name;
}
public MyCalendarFixture createFixture(Robot robot, Container root) {
MyCalendar calendar = robot.finder().findByName(root, name, MyCalendar.class, true);
return new MyCalendarFixture(robot, calendar);
}
}</code></pre>
<p>The only method that needs to be implemented is <code>createFixture(Robot, Container)</code>, which is
responsible for creating our custom fixture. The static method <code>calendarWithName(String)</code> is just
a convenience factory method, which we will use to connect our extension to any implementation of
<code>AbstractContainerFixture</code>:</p>
<pre><code class="language-java">// import static org.assertj.swing.sample.MyCalendarFixtureExtension.calendarWithName;
FrameFixture frame = new FrameFixture(new MyFrame());
frame.with(calendarWithName("myCalendar")).selectDate("10/18/08");</code></pre>
<h2>Handling System.exit</h2>
<p>A common topic in the mailing list is how to handle <code>System.exit</code>. The typical example is
simulating a user selecting the menus <em>File</em>, <em>Exit</em> from a GUI test. By doing this, the
application will quit and any GUI test trying to use the application will fail.</p>
<p>To prevent this failure and to test that in fact <code>System.exit</code> is being handled correctly by the
application, AssertJ Swing provides a <code>NoExitSecurityManager</code> that will prevent the
application to end. To use it, simply add a call to <code>NoExitSecurityManagerInstaller</code> as
follows:</p>
<pre class="pre-scrollable"><code class="language-java">private static NoExitSecurityManagerInstaller noExitSecurityManagerInstaller;
@BeforeClass
public static void setUpOnce() {
noExitSecurityManagerInstaller = NoExitSecurityManagerInstaller.install();
}
@AfterClass
public static void tearDown() {
noExitSecurityManagerInstaller.uninstall();
}</code></pre>
<p>By default, <code>NoExitSecurityManager</code> will just prevent the application from quitting if
<code>System.exit</code> is called. If you want to do something when <code>System.exit</code> is called, do
the following:</p>
<ul>
<li>Implement a <code>ExitHook</code></li>
<li>Pass an instance of your <code>ExitHook</code> to
<code>NoExitSecurityManagerInstaller.install(ExitHook)</code></li>
</ul>
<h2>Support for Platform-Specific Features</h2>
<p>Sometimes, when testing our applications, we need to deal with platform-specific issues.
AssertJ Swing provides the utility class <code>Platform</code> to overcome this type of issues.</p>
<p>Currently <code>Platform</code> provides one method, <code>controlOrCommandKey()</code> that returns the
code of either the <em>Command</em> key (if MacOS) or the code of the <em>Control</em> key (if other than
MacOS, for example Windows). A good example of the utility of this method is simulation of a user copying
some text to the clipboard. In windows we need to simulate a user pressing the keys <kbd>Ctrl</kbd> and
<kbd>C</kbd>, while in MacOS we need to simulate a user pressing the keys <kbd>Cmd</kbd> and
<kbd>C</kbd>. With AssertJ Swing we can simply write:</p>
<pre><code class="language-java">// import static org.assertj.swing.util.Platform.controlOrCommandKey;
// import static java.awt.event.KeyEvent.VK_C;
int controlOrCommand = controlOrCommandKey();
dialog.textBox("username").selectAll()
.pressKey(controlOrCommand)
.pressAndReleaseKeys(VK_C)
.releaseKey(controlOrCommand);</code></pre>
<h2>Testing containers without a frame</h2>
<p>AssertJ Swing provides the utility class <code>Containers</code> to help test a <code>Container</code>
(e.g. a <code>JPanel</code>) without having a <code>Frame</code> (or <code>JFrame</code>). The following
code listing shows how to test our own <code>JPanel</code> of type <code>MyCoolJPanel</code>:</p>
<pre><code class="language-jave">// import static org.assertj.swing.fixture.Containers.showInFrame;
private FrameFixture frameFixture;
@Before
public void setUp() {
MyCoolJPanel panel = createPanel() // create panel in EDT.
frameFixture = showInFrame(panel);
}</code></pre>
<p>AssertJ Swing will show the panel in a <code>JFrame</code>, wrapped in a <code>FrameFixture</code>.</p>
</div>
</div>
</div>
<br>
<!--
<div class="container">
<footer>
<div class="row">
<div class="col-lg-12">
<p>AssertJ - Licensed under the Apache License, Version 2.0.</p>
</div>
</div>
</footer>
</div>
-->
<script src="js/jquery-1.10.2.js"></script>
<script src="js/bootstrap.js"></script>
<script src="js/modern-business.js"></script>
<script src="js/assertj.js"></script>
</body>
</html>