kookaburra 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.travis.yml +1 -3
- data/README.markdown +259 -181
- data/Rakefile +11 -2
- data/kookaburra.gemspec +1 -0
- data/lib/kookaburra.rb +24 -9
- data/lib/kookaburra/api_client.rb +1 -1
- data/lib/kookaburra/api_driver.rb +1 -1
- data/lib/kookaburra/assertion.rb +1 -1
- data/lib/kookaburra/configuration.rb +25 -9
- data/lib/kookaburra/configuration/proxy.rb +55 -0
- data/lib/kookaburra/dependency_accessor.rb +7 -0
- data/lib/kookaburra/exceptions.rb +11 -3
- data/lib/kookaburra/mental_model.rb +5 -5
- data/lib/kookaburra/rack_app_server.rb +3 -12
- data/lib/kookaburra/test_helpers.rb +53 -12
- data/lib/kookaburra/ui_driver/ui_component.rb +9 -2
- data/lib/kookaburra/version.rb +1 -1
- data/spec/integration/test_a_rack_application_spec.rb +3 -2
- data/spec/integration/test_multiple_applications_spec.rb +96 -0
- data/spec/kookaburra/api_client_spec.rb +6 -5
- data/spec/kookaburra/api_driver_spec.rb +18 -0
- data/spec/kookaburra/configuration/proxy_spec.rb +39 -0
- data/spec/kookaburra/configuration_spec.rb +54 -2
- data/spec/kookaburra/mental_model_spec.rb +22 -20
- data/spec/kookaburra/test_helpers_spec.rb +60 -24
- data/spec/kookaburra/ui_driver/scoped_browser_spec.rb +3 -2
- data/spec/kookaburra/ui_driver/ui_component/address_bar_spec.rb +2 -1
- data/spec/kookaburra/ui_driver/ui_component_spec.rb +48 -14
- data/spec/kookaburra/ui_driver_spec.rb +4 -3
- data/spec/kookaburra_spec.rb +19 -14
- data/spec/spec_helper.rb +79 -0
- data/spec/support/shared_examples/it_can_have_ui_components.rb +2 -2
- data/spec/support/shared_examples/it_can_make_assertions.rb +3 -3
- data/spec/support/shared_examples/it_has_a_dependency_accessor.rb +3 -4
- metadata +25 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40ba91318bee567ced157fa2bd8d51367a88e584
|
4
|
+
data.tar.gz: 6a4c31b072f15bf12fb4802910172a385daab48b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 857eaede49769932c27334a67814fe48a150195085068d33391b5a59b123885bdaa428f4340b85eb40886371dd802dd893410d4ce04f958f829183db747379e8
|
7
|
+
data.tar.gz: a8a53de66691968681c4a8765f2fef89c668ec132fd23ae17e95daf825392a36ae588f692379ca2512e40f9e82a282f0a67a914f34522b87ad7666ebcf894b7c
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/README.markdown
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
# Kookaburra #
|
2
2
|
|
3
|
-
Kookaburra is a framework for implementing the [Window Driver] [Window Driver]
|
4
|
-
order to keep acceptance tests maintainable.
|
3
|
+
Kookaburra is a framework for implementing the [Window Driver] [Window Driver]
|
4
|
+
pattern in order to keep acceptance tests maintainable.
|
5
|
+
|
6
|
+
[![Code Climate](https://codeclimate.com/github/jwilger/kookaburra/badges/gpa.svg)](https://codeclimate.com/github/jwilger/kookaburra)
|
7
|
+
[![Test Coverage](https://codeclimate.com/github/jwilger/kookaburra/badges/coverage.svg)](https://codeclimate.com/github/jwilger/kookaburra)
|
5
8
|
|
6
9
|
## Requirements ##
|
7
10
|
|
8
|
-
Requires Ruby 1.
|
9
|
-
that you must run JRuby in 1.9 compatability mode.)
|
11
|
+
Requires Ruby 2.1.0 or greater.
|
10
12
|
|
11
13
|
## Installation ##
|
12
14
|
|
13
|
-
Kookaburra is available as a Rubygem and
|
14
|
-
so installation is trivial:
|
15
|
+
Kookaburra is available as a Rubygem and
|
16
|
+
[published on Rubygems.org] [Kookaburra Gem], so installation is trivial:
|
15
17
|
|
16
18
|
gem install kookaburra
|
17
19
|
|
@@ -24,51 +26,53 @@ following:
|
|
24
26
|
|
25
27
|
## Setup ##
|
26
28
|
|
27
|
-
Kookaburra abstracts some common patterns for implementing the Window
|
28
|
-
testing pattern for web applications. You will need to tell
|
29
|
-
classes contain the specific Domain Driver
|
30
|
-
as well as which driver to use for
|
31
|
-
[Capybara] [Capybara]).
|
32
|
-
|
33
|
-
Kookaburra is designed to run tests
|
34
|
-
server could be running on the same machine, it
|
35
|
-
|
36
|
-
running.
|
37
|
-
|
38
|
-
The fact that Kookaburra runs against a remote server means that *it is
|
39
|
-
limited to testing only Ruby web applications*. As long as your
|
40
|
-
exposes a web-service API for use by the APIDriver and an
|
41
|
-
for use by the UIDriver, you can use Kookaburra to
|
42
|
-
you're careful with both your application and
|
43
|
-
to running your tests only in an
|
44
|
-
|
45
|
-
systems.
|
29
|
+
Kookaburra abstracts some common patterns for implementing the Window
|
30
|
+
Driver testing pattern for web applications. You will need to tell
|
31
|
+
Kookaburra which classes contain the specific Domain Driver
|
32
|
+
implementations for your application as well as which driver to use for
|
33
|
+
running the tests (currently only tested with [Capybara] [Capybara]).
|
34
|
+
|
35
|
+
Kookaburra is designed to run tests against one or more remote web
|
36
|
+
servers (although the server(s) could be running on the same machine, it
|
37
|
+
doesn't need to be), and it is the responsibility of the test
|
38
|
+
implementation to ensure that the server is running.
|
39
|
+
|
40
|
+
The fact that Kookaburra runs against a remote server means that *it is
|
41
|
+
not limited to testing only Ruby web applications*. As long as your
|
42
|
+
application exposes a web-service API for use by the APIDriver and an
|
43
|
+
HTML user interface for use by the UIDriver, you can use Kookaburra to
|
44
|
+
test it. Also, as long as you're careful with both your application and
|
45
|
+
test designs, you're not limited to running your tests only in an
|
46
|
+
isolated testing environment; you could run the same test suite you use
|
47
|
+
for development against your staging or production systems.
|
46
48
|
|
47
49
|
### Testing an Application Running Locally ###
|
48
50
|
|
49
|
-
The fact that Kookaburra is designed to support running tests against a
|
50
|
-
server does not, of course, mean that the application cannot be
|
51
|
-
It is possible to have your test suite manage the
|
52
|
-
stopping your server for you. Examples of how
|
53
|
-
are presented below, but you should be
|
54
|
-
other types of application
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
51
|
+
The fact that Kookaburra is designed to support running tests against a
|
52
|
+
remote server does not, of course, mean that the application cannot be
|
53
|
+
running locally. It is possible to have your test suite manage the
|
54
|
+
process of starting and stopping your server(s) for you. Examples of how
|
55
|
+
to do so with a Rack application are presented below, but you should be
|
56
|
+
able to take the same basic approach with other types of application
|
57
|
+
servers.
|
58
|
+
|
59
|
+
Although Capybara is capable of starting a Rack application server on
|
60
|
+
its own, the default setup only starts the server up on-demand when you
|
61
|
+
call a method that requires the browser to interact with the web
|
62
|
+
application. Because the APIClient layer does not use Capybara, it is
|
63
|
+
necessary to manage the server process on your own. Otherwise the server
|
64
|
+
would not be guaranteed to be running when you call the APIClient
|
65
|
+
methods (particularly as these often appear in "Given" statements that
|
63
66
|
are run before you start interacting with the web browser.)
|
64
67
|
|
65
|
-
Keep in mind that, even if your server is capable of being started up in
|
66
|
-
thread within the same Ruby process that is executing your test
|
67
|
-
want to avoid doing so unless you are using a Ruby
|
68
|
-
native threads. Otherwise, when the APIClient
|
69
|
-
application's API, it will block while
|
70
|
-
|
71
|
-
timeout error in your
|
68
|
+
**Keep in mind that, even if your server is capable of being started up in
|
69
|
+
another thread within the same Ruby process that is executing your test
|
70
|
+
suite, you will want to avoid doing so unless you are using a Ruby
|
71
|
+
interpreter that supports native threads. Otherwise, when the APIClient
|
72
|
+
makes an HTTP call to your application's API, it will block while
|
73
|
+
waiting for a response, thus preventing your application from being able
|
74
|
+
to respond to that request and resulting in a timeout error in your
|
75
|
+
tests.**
|
72
76
|
|
73
77
|
### RSpec ###
|
74
78
|
|
@@ -106,13 +110,46 @@ add the following to `spec/support/kookaburra_setup.rb`:
|
|
106
110
|
c.include(Kookaburra::TestHelpers, :type => :request)
|
107
111
|
end
|
108
112
|
|
113
|
+
#### Testing Multiple Applications
|
114
|
+
|
115
|
+
Sometimes you need to test a business process that spans multiple
|
116
|
+
"applications" in your platform. Kookaburra can be configured to operate
|
117
|
+
against multiple remote applications by defining them in the
|
118
|
+
configuration block as follows:
|
119
|
+
|
120
|
+
Kookaburra.configure do |c|
|
121
|
+
c.application(:app_one) do |a|
|
122
|
+
a.api_driver_class = AppOne::APIDriver
|
123
|
+
a.ui_driver_class = AppOne::UIDriver
|
124
|
+
a.app_host = 'http://app_one.example.com:1234'
|
125
|
+
end
|
126
|
+
|
127
|
+
c.application(:app_two) do |a|
|
128
|
+
a.api_driver_class = AppTwo::APIDriver
|
129
|
+
a.ui_driver_class = AppTwo::UIDriver
|
130
|
+
a.app_host = 'http://app_two.example.com:1234'
|
131
|
+
end
|
132
|
+
|
133
|
+
c.browser = Capybara::Session.new(:selenium)
|
134
|
+
c.server_error_detection { |browser|
|
135
|
+
browser.has_css?('head title', :text => 'Internal Server Error')
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
This changes the way you use the `#api` and `#ui` test helpers
|
140
|
+
(explained below) so that you must qualify each one with the name of the
|
141
|
+
application, i.e. `#app_one.api`, and `#app_two.ui`. Configuration
|
142
|
+
parameters set on the base configuration (e.g. `c.browser = #...`) are
|
143
|
+
shared between all named applications that do not specifically override
|
144
|
+
them.
|
145
|
+
|
109
146
|
#### Managing startup and shutdown of a Rack application server ####
|
110
147
|
|
111
|
-
While developing, it can be helpful to run your integration specs
|
112
|
-
locally-running server that is managed by your test suite. The
|
113
|
-
to that in the previous section, but it adds before and
|
114
|
-
and shut down a Rack application server. Just add
|
115
|
-
`spec/support/kookaburra_setup.rb`:
|
148
|
+
While developing, it can be helpful to run your integration specs
|
149
|
+
against a locally-running server that is managed by your test suite. The
|
150
|
+
setup is similar to that in the previous section, but it adds before and
|
151
|
+
after hooks to launch and shut down a Rack application server. Just add
|
152
|
+
the following to `spec/support/kookaburra_setup.rb`:
|
116
153
|
|
117
154
|
require 'kookaburra/test_helpers'
|
118
155
|
require 'kookaburra/rack_app_server'
|
@@ -157,14 +194,15 @@ and shut down a Rack application server. Just add the following to
|
|
157
194
|
|
158
195
|
### Cucumber ###
|
159
196
|
|
160
|
-
The following examples depict how you might configure [Cucumber]
|
161
|
-
run tests against an already running application server
|
162
|
-
site) and a Rack application server that is
|
197
|
+
The following examples depict how you might configure [Cucumber]
|
198
|
+
[Cucumber] to run tests against an already running application server
|
199
|
+
(e.g. a remote staging site) and a Rack application server that is
|
200
|
+
managed by the test suite.
|
163
201
|
|
164
202
|
#### Testing an already running server ####
|
165
203
|
|
166
|
-
If you are running your tests against an already running server, you can
|
167
|
-
add the following to `features/support/kookaburra_setup.rb`:
|
204
|
+
If you are running your tests against an already running server, you can
|
205
|
+
simply add the following to `features/support/kookaburra_setup.rb`:
|
168
206
|
|
169
207
|
require 'kookaburra/test_helpers'
|
170
208
|
|
@@ -187,13 +225,46 @@ add the following to `features/support/kookaburra_setup.rb`:
|
|
187
225
|
|
188
226
|
World(Kookaburra::TestHelpers)
|
189
227
|
|
228
|
+
#### Testing Multiple Applications
|
229
|
+
|
230
|
+
Sometimes you need to test a business process that spans multiple
|
231
|
+
"applications" in your platform. Kookaburra can be configured to operate
|
232
|
+
against multiple remote applications by defining them in the
|
233
|
+
configuration block as follows:
|
234
|
+
|
235
|
+
Kookaburra.configure do |c|
|
236
|
+
c.application(:app_one) do |a|
|
237
|
+
a.api_driver_class = AppOne::APIDriver
|
238
|
+
a.ui_driver_class = AppOne::UIDriver
|
239
|
+
a.app_host = 'http://app_one.example.com:1234'
|
240
|
+
end
|
241
|
+
|
242
|
+
c.application(:app_two) do |a|
|
243
|
+
a.api_driver_class = AppTwo::APIDriver
|
244
|
+
a.ui_driver_class = AppTwo::UIDriver
|
245
|
+
a.app_host = 'http://app_two.example.com:1234'
|
246
|
+
end
|
247
|
+
|
248
|
+
c.browser = Capybara::Session.new(:selenium)
|
249
|
+
c.server_error_detection { |browser|
|
250
|
+
browser.has_css?('head title', :text => 'Internal Server Error')
|
251
|
+
}
|
252
|
+
end
|
253
|
+
|
254
|
+
This changes the way you use the `#api` and `#ui` test helpers
|
255
|
+
(explained below) so that you must qualify each one with the name of the
|
256
|
+
application, i.e. `#app_one.api`, and `#app_two.ui`. Configuration
|
257
|
+
parameters set on the base configuration (e.g. `c.browser = #...`) are
|
258
|
+
shared between all named applications that do not specifically override
|
259
|
+
them.
|
260
|
+
|
190
261
|
#### Managing startup and shutdown of a Rack application server ####
|
191
262
|
|
192
|
-
While developing, it can be helpful to run your acceptance tests against
|
193
|
-
locally-running server that is managed by your test suite. The setup
|
194
|
-
to that in the previous section, but it adds before and after
|
195
|
-
and shut down a Rack application server. Just add the
|
196
|
-
`features/support/kookaburra_setup.rb`:
|
263
|
+
While developing, it can be helpful to run your acceptance tests against
|
264
|
+
a locally-running server that is managed by your test suite. The setup
|
265
|
+
is similar to that in the previous section, but it adds before and after
|
266
|
+
hooks to launch and shut down a Rack application server. Just add the
|
267
|
+
following to `features/support/kookaburra_setup.rb`:
|
197
268
|
|
198
269
|
require 'kookaburra/test_helpers'
|
199
270
|
require 'kookaburra/rack_app_server'
|
@@ -234,10 +305,10 @@ and shut down a Rack application server. Just add the following to
|
|
234
305
|
|
235
306
|
## Defining Your Testing DSL ##
|
236
307
|
|
237
|
-
Kookaburra extracts some common patterns that make it easier to use the
|
238
|
-
Driver pattern along with various Ruby testing frameworks, but
|
239
|
-
define your own testing DSL. An acceptance testing
|
240
|
-
the following layers:
|
308
|
+
Kookaburra extracts some common patterns that make it easier to use the
|
309
|
+
Window Driver pattern along with various Ruby testing frameworks, but
|
310
|
+
you still need to define your own testing DSL. An acceptance testing
|
311
|
+
stack using Kookaburra has the following layers:
|
241
312
|
|
242
313
|
1. The **Business Specification Language** (Cucumber scenarios or other
|
243
314
|
spcification documents)
|
@@ -249,12 +320,12 @@ the following layers:
|
|
249
320
|
|
250
321
|
### The Business Specification Language ###
|
251
322
|
|
252
|
-
The business specification language consists of the highest-level
|
253
|
-
of a feature that are suitable for sharing with the
|
254
|
-
stakeholders on a project.
|
323
|
+
The business specification language consists of the highest-level
|
324
|
+
descriptions of a feature that are suitable for sharing with the
|
325
|
+
non/less-technical stakeholders on a project.
|
255
326
|
|
256
|
-
Gherkin is the external DSL used by Cucumber for this purpose, and you
|
257
|
-
have the following scenario defined for an e-commerce application:
|
327
|
+
Gherkin is the external DSL used by Cucumber for this purpose, and you
|
328
|
+
might have the following scenario defined for an e-commerce application:
|
258
329
|
|
259
330
|
# purchase_items_in_cart.feature
|
260
331
|
|
@@ -274,40 +345,38 @@ have the following scenario defined for an e-commerce application:
|
|
274
345
|
And I see that my default payment options will be used
|
275
346
|
And I see that my default shipping options will be used
|
276
347
|
|
277
|
-
Note that the scenario is focused on business concepts versus interface
|
278
|
-
i.e. you "choose to check out" rather than "click on the
|
279
|
-
for some reason your e-commerce system was going to
|
280
|
-
rather than a web application, you would not
|
281
|
-
all, because the actual business
|
282
|
-
although Kookaburra's focus is
|
283
|
-
adapted to other
|
348
|
+
Note that the scenario is focused on business concepts versus interface
|
349
|
+
details, i.e. you "choose to check out" rather than "click on the
|
350
|
+
checkout button". If for some reason your e-commerce system was going to
|
351
|
+
be a terminal application rather than a web application, you would not
|
352
|
+
need to change this scenario at all, because the actual business
|
353
|
+
concepts described would not change (and although Kookaburra's focus is
|
354
|
+
on testing web applications, it could likely be adapted to other
|
355
|
+
environments.)
|
284
356
|
|
285
357
|
### The Test Implementation ###
|
286
358
|
|
287
359
|
The Test Implementation layer exists as the line in between the Business
|
288
|
-
Specification Language and the Domain Driver, and it includes Cucumber
|
289
|
-
definitions, RSpec example blocks, Test::Unit tests, etc. At this
|
290
|
-
code orchestrates calls into the Domain Driver to mimic user
|
291
|
-
various conditions and make assertions about the
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
mental model. If you are using Test::Unit, see
|
309
|
-
`Kookaburra::TestHelpers#assert_mental_model_of`; for RSpec, see
|
310
|
-
`Kookaburra::TestHelpers#match_mental_model_of`.
|
360
|
+
Specification Language and the Domain Driver, and it includes Cucumber
|
361
|
+
step definitions, RSpec example blocks, Test::Unit tests, etc. At this
|
362
|
+
layer, your code orchestrates calls into the Domain Driver to mimic user
|
363
|
+
interactions under various conditions and make assertions about the
|
364
|
+
results.
|
365
|
+
|
366
|
+
**Test assertions always belong within the test implementation layer.**
|
367
|
+
Some testing frameworks such as RSpec add methods like `#should` to
|
368
|
+
`Object`, which has the effect of poisoning the entire Ruby namespace
|
369
|
+
with these methods---if you are using RSpec, you can call `#should`
|
370
|
+
anywhere in your code and it will work when RSpec is loaded. Do not be
|
371
|
+
tempted to call a testing library's Object decorators anywhere outside
|
372
|
+
of your test implementation (such as within `UIDriver` or `UIComponent`
|
373
|
+
subclasses.) Doing so will tightly couple your Domain Driver and/or
|
374
|
+
Window Driver implementation to a specific testing library.
|
375
|
+
|
376
|
+
`Kookaburra::UIDriver::UIComponent` provides an `#assert` method for use
|
377
|
+
inside your own UIComponents. This method exists to verify preconditions
|
378
|
+
and provide more informative error messages; it is not intended to be
|
379
|
+
used for test verifications.
|
311
380
|
|
312
381
|
Given the Cucumber scenario above, here is how the test implementation layer
|
313
382
|
might look:
|
@@ -343,24 +412,26 @@ might look:
|
|
343
412
|
end
|
344
413
|
|
345
414
|
Then "I see that my default payment options will be used" do
|
346
|
-
ui.order_summary.payment_options.
|
347
|
-
|
348
|
-
# assert_mental_model_matches(:default_payment_options, ui.order_summary.payment_options)
|
415
|
+
expect(ui.order_summary.payment_options).to \
|
416
|
+
eq get_data(:payment_optons)[:default]
|
349
417
|
end
|
350
418
|
|
351
419
|
Then "I see that my default shipping options will be used" do
|
352
|
-
ui.order_summary.shipping_options.
|
420
|
+
expect(ui.order_summary.shipping_options).to \
|
421
|
+
eq get_data(:shipping_options)[:default]
|
353
422
|
end
|
354
423
|
|
355
424
|
The step definitions contain neither explicitly shared state (instance
|
356
|
-
variables) nor any logic branches; they are simply wrappers around calls
|
357
|
-
the Domain Driver layer. There are a couple of advantages to this
|
425
|
+
variables) nor any logic branches; they are simply wrappers around calls
|
426
|
+
into the Domain Driver layer. There are a couple of advantages to this
|
427
|
+
approach.
|
358
428
|
|
359
|
-
First, because step definitions are so simple, it isn't necessary to
|
360
|
-
Specific Wording* on the business analyst/product owner who
|
361
|
-
specs. For instance, if she writes "I see a summary of my
|
362
|
-
scenario, it's not a big deal to have the following in
|
363
|
-
long as the author of the spec confirms that
|
429
|
+
First, because step definitions are so simple, it isn't necessary to
|
430
|
+
force *Very Specific Wording* on the business analyst/product owner who
|
431
|
+
is writing the specs. For instance, if she writes "I see a summary of my
|
432
|
+
order" in another scenario, it's not a big deal to have the following in
|
433
|
+
your step definitions (as long as the author of the spec confirms that
|
434
|
+
they really mean the same thing):
|
364
435
|
|
365
436
|
Then "I see my order summary" do
|
366
437
|
ui.order_summary.should be_visible
|
@@ -370,18 +441,18 @@ long as the author of the spec confirms that they really mean the same thing):
|
|
370
441
|
ui.order_summary.should be_visible
|
371
442
|
end
|
372
443
|
|
373
|
-
The step definitions are nothing more than a natural language reference
|
374
|
-
action in the Domain Driver; there is no overwhelming maintenance
|
375
|
-
slight duplication, and it opens up the capacity for more
|
376
|
-
specs. The fewer false road blocks you put between your
|
377
|
-
written specification, the easier it becomes to
|
378
|
-
process.
|
444
|
+
The step definitions are nothing more than a natural language reference
|
445
|
+
to an action in the Domain Driver; there is no overwhelming maintenance
|
446
|
+
cost to the slight duplication, and it opens up the capacity for more
|
447
|
+
readable Gherkin specs. The fewer false road blocks you put between your
|
448
|
+
product owner and a written specification, the easier it becomes to
|
449
|
+
ensure her participation in this process.
|
379
450
|
|
380
|
-
The second advantage is that by pushing all of the complexity down into
|
381
|
-
Domain Driver, it's now trivial to reuse the exact same code in
|
382
|
-
developer-centric integration tests. This ensures you have parity
|
383
|
-
way the automated acceptance tests run and any additional
|
384
|
-
development team needs to add in.
|
451
|
+
The second advantage is that by pushing all of the complexity down into
|
452
|
+
the Domain Driver, it's now trivial to reuse the exact same code in
|
453
|
+
developer-centric integration tests. This ensures you have parity
|
454
|
+
between the way the automated acceptance tests run and any additional
|
455
|
+
testing that the development team needs to add in.
|
385
456
|
|
386
457
|
Using RSpec, the test implementation would be as follows:
|
387
458
|
|
@@ -390,52 +461,58 @@ Using RSpec, the test implementation would be as follows:
|
|
390
461
|
describe "Purchase Items in Cart" do
|
391
462
|
example "Using Existing Billing and Shipping Information" do
|
392
463
|
api.existing_account(:my_account)
|
393
|
-
api.
|
394
|
-
api.
|
395
|
-
api.an_item_in_my_shopping_cart
|
464
|
+
api.default_payment_options_specified
|
465
|
+
api.default_shipping_options_specified
|
466
|
+
api.an_item_in_my_shopping_cart
|
396
467
|
|
397
|
-
ui.sign_in
|
468
|
+
ui.sign_in
|
398
469
|
ui.choose_to_check_out
|
399
470
|
|
400
|
-
ui.order_summary.
|
401
|
-
ui.order_summary.payment_options.
|
402
|
-
|
471
|
+
expect(ui.order_summary).to be_visible
|
472
|
+
expect(ui.order_summary.payment_options).to \
|
473
|
+
eq get_data(:payment_optons)[:default]
|
474
|
+
|
475
|
+
expect(ui.order_summary.shipping_options).to \
|
476
|
+
eq get_data(:shipping_options)[:default]
|
403
477
|
end
|
404
478
|
end
|
405
479
|
|
406
480
|
### The Domain Driver ###
|
407
481
|
|
408
|
-
The Domain Driver layer is where you build up an internal DSL that
|
409
|
-
business concepts of your application at a fairly high
|
410
|
-
top-level drivers: the `APIDriver` (available
|
411
|
-
state for your tests and the UIDriver
|
412
|
-
tasks that a user can
|
482
|
+
The Domain Driver layer is where you build up an internal DSL that
|
483
|
+
describes the business concepts of your application at a fairly high
|
484
|
+
level. It consists of two top-level drivers: the `APIDriver` (available
|
485
|
+
via `#api`) used to set up state for your tests and the UIDriver
|
486
|
+
(available via `#ui`) for describing the tasks that a user can
|
487
|
+
accomplish with the application.
|
413
488
|
|
414
489
|
#### Mental Model ####
|
415
490
|
|
416
|
-
`Kookaburra::MentalModel` is the component via which the `APIDriver` and
|
417
|
-
`UIDriver` share information, and it is intended to represent your
|
418
|
-
user's mental picture of the data they are working with. For
|
419
|
-
create a user account via the `APIDriver`, you would
|
420
|
-
credentials for that account in the `MentalModel`
|
421
|
-
knows what to use when you tell it to
|
422
|
-
Cucumber step definitions to remain
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
`
|
436
|
-
|
437
|
-
|
438
|
-
|
491
|
+
`Kookaburra::MentalModel` is the component via which the `APIDriver` and
|
492
|
+
the `UIDriver` share information, and it is intended to represent your
|
493
|
+
application user's mental picture of the data they are working with. For
|
494
|
+
instance, if you create a user account via the `APIDriver`, you would
|
495
|
+
store the login credentials for that account in the `MentalModel`
|
496
|
+
instance, so the `UIDriver` knows what to use when you tell it to
|
497
|
+
`#sign_in`. This is what allows the Cucumber step definitions to remain
|
498
|
+
free from explicitly shared state.
|
499
|
+
|
500
|
+
Kookaburra automatically configures your `APIDriver` and your `UIDriver`
|
501
|
+
to share a `MentalModel` instance, which is available to both of them
|
502
|
+
via their `#mental_model` method.
|
503
|
+
|
504
|
+
The `MentalModel` instance will return a `MentalModel::Collection` for
|
505
|
+
any method called on the object. The `MentalModel::Collection` object
|
506
|
+
behaves like a `Hash` for the most part; however, it will raise a
|
507
|
+
`Kookaburra::UnknownKeyError` if you try to access a key that has not
|
508
|
+
yet been assigned a value.
|
509
|
+
|
510
|
+
Deletions (via `#delete` or `#delete_if`) will actually remove the
|
511
|
+
key/value pair from the collection, but add it to a sub-collection
|
512
|
+
(available at `MentalModel::Collection#deleted`). This reflects the fact
|
513
|
+
that the user's mental model of the dataset would also include any
|
514
|
+
intentional exceptions - the user will, for example, want to verify that
|
515
|
+
an item they deleted does not appear to be available in the system.
|
439
516
|
|
440
517
|
Here's an example of MentalModel behavior:
|
441
518
|
|
@@ -461,11 +538,11 @@ Here's an example of MentalModel behavior:
|
|
461
538
|
|
462
539
|
#### API Driver ####
|
463
540
|
|
464
|
-
The `Kookaburra::APIDriver` is used to create a particular "preexisting"
|
465
|
-
within your application's data and ensure you have a handle to
|
466
|
-
needed) prior to interacting with the UI. You will
|
467
|
-
`Kookaburra::APIDriver` in which you will create
|
468
|
-
for your application:
|
541
|
+
The `Kookaburra::APIDriver` is used to create a particular "preexisting"
|
542
|
+
state within your application's data and ensure you have a handle to
|
543
|
+
that data (when needed) prior to interacting with the UI. You will
|
544
|
+
create a subclass of `Kookaburra::APIDriver` in which you will create
|
545
|
+
part of the Domain Driver DSL for your application:
|
469
546
|
|
470
547
|
# lib/my_app/kookaburra/api_driver.rb
|
471
548
|
|
@@ -521,9 +598,9 @@ paths.
|
|
521
598
|
#### UI Driver ####
|
522
599
|
|
523
600
|
`Kookaburra::UIDriver` provides the necessary tools for driving your
|
524
|
-
application's user interface with the Window Driver pattern. You will
|
525
|
-
`Kookaburra::UIDriver` for your application and implement your
|
526
|
-
within your subclass:
|
601
|
+
application's user interface with the Window Driver pattern. You will
|
602
|
+
subclass `Kookaburra::UIDriver` for your application and implement your
|
603
|
+
testing DSL within your subclass:
|
527
604
|
|
528
605
|
# lib/my_app/kookaburra/ui_driver.rb
|
529
606
|
|
@@ -541,15 +618,16 @@ within your subclass:
|
|
541
618
|
|
542
619
|
### The Window Driver Layer ###
|
543
620
|
|
544
|
-
While your `APIDriver` and `UIDriver` provide a DSL that represents
|
545
|
-
your users can perform in your application, the
|
546
|
-
layer describes the individual user
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
621
|
+
While your `APIDriver` and `UIDriver` provide a DSL that represents
|
622
|
+
actions your users can perform in your application, the
|
623
|
+
[Window Driver] [Window Driver] layer describes the individual user
|
624
|
+
interface components that the user interacts with to perform these
|
625
|
+
tasks. By describing each interface component using an OOP approach, it
|
626
|
+
is much easier to maintain your acceptance/integration tests, because
|
627
|
+
the implementation details of each component are captured in a single
|
628
|
+
place. For example, if/when the implementation of your application's
|
629
|
+
sign in screen changes, you can fix every single test that needs to log
|
630
|
+
a user into the system just by updating the `SignInScreen` class.
|
553
631
|
|
554
632
|
You describe the various user interface components by sub-classing
|
555
633
|
`Kookaburra::UIDriver::UIComponent`:
|
@@ -603,11 +681,12 @@ whatever is passed to `Kookaburra.new` as the `:browser` option.
|
|
603
681
|
Presently, we have only used Capybara as the application driver for
|
604
682
|
Kookaburra.
|
605
683
|
|
606
|
-
It's possible that something other than Capybara could be passed in, as
|
607
|
-
that something presented the same API. In reality, using
|
608
|
-
Capybara is likely to require some changes to
|
609
|
-
|
610
|
-
and send us a [GitHub pull
|
684
|
+
It's possible that something other than Capybara could be passed in, as
|
685
|
+
long as that something presented the same API. In reality, using
|
686
|
+
something other than Capybara is likely to require some changes to
|
687
|
+
Kookaburra itself. If you have a particular interest in making this
|
688
|
+
work, please feel free to fork the project and send us a [GitHub pull
|
689
|
+
request] [Pull Request] with your changes.
|
611
690
|
|
612
691
|
## Contributing to kookaburra ##
|
613
692
|
|
@@ -627,8 +706,7 @@ and send us a [GitHub pull request] [Pull Request] with your changes.
|
|
627
706
|
|
628
707
|
## Copyright ##
|
629
708
|
|
630
|
-
Copyright © 2011 John Wilger. See LICENSE.txt for
|
631
|
-
further details.
|
709
|
+
Copyright © 2011 John Wilger. See LICENSE.txt for further details.
|
632
710
|
|
633
711
|
[Window Driver]: http://martinfowler.com/eaaDev/WindowDriver.html "Window Driver - Martin Fowler"
|
634
712
|
[Kookaburra Gem]: https://rubygems.org/gems/kookaburra "kookaburra | RubyGems.org | your community gem host"
|