kookaburra 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](https://codeclimate.com/github/jwilger/kookaburra)
|
7
|
+
[](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"
|