Skip to content
This repository was archived by the owner on Dec 21, 2024. It is now read-only.

Commit 9347311

Browse files
authored
Update state to be polyglot (Fixes #362) (#432)
* Update state to be polyglot (fixes #362) * Update content/docs/cucumber/state.md * Update content/docs/cucumber/state.md * Update content/docs/cucumber/state.md
1 parent d23fe66 commit 9347311

File tree

1 file changed

+102
-44
lines changed

1 file changed

+102
-44
lines changed

content/docs/cucumber/state.md

+102-44
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
---
22
title: State
33
subtitle: Sharing state, isolated state, dependency injection
4+
polyglot:
5+
- java
6+
- javascript
7+
- ruby
8+
- kotlin
49
---
510

611
It's important to prevent state created by one scenario from leaking into others.
@@ -24,6 +29,7 @@ State can make your steps more tightly coupled and harder to reuse.
2429

2530
## World object
2631

32+
{{% block "ruby" %}}
2733
In Ruby, Cucumber runs scenarios in a `World`. By default, the `World` is an instance of `Object`.
2834

2935
All [step definitions](/docs/cucumber/step-definitions) will run in the context of the current `World` instance; a new instance
@@ -91,14 +97,21 @@ World(MyHelper, MyOtherHelpers)
9197
This will `extend` each new `World` object with those modules.
9298

9399
If you use [Ruby on Rails](/docs/tools/ruby#ruby-on-rails), there is already a `World` set up for you, so you will get
94-
an instance of `Cucumber::Rails::World`, which is a subclass of `ActionDispatch::IntegrationTest`. This gives you access to a lot of Rails' helper methods.
100+
an instance of `Cucumber::Rails::World`, which is a subclass of `ActionDispatch::IntegrationTest`. This gives you access
101+
to a lot of Rails' helper methods.
102+
{{% /block %}}
95103

96-
Cucumber-js also uses a `World` as an isolated context for each scenario. You can find more information in the
104+
{{% block "javascript" %}} Cucumber-js uses a `World` as an isolated context for each scenario. You can find more
105+
information in the
97106
[cucumber-js documentation on GitHub](https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/world.md).
107+
{{% /block %}}
108+
109+
{{% block "java,kotlin" %}} JVM languages do not know a "World" object, like Ruby and JavaScript. Instead, you'll need
110+
to use [Dependency Injection](#dependency-injection).{{% /block %}}
98111

99112
## Dependency Injection
100-
If your programming language is Java, you will be writing glue code
101-
([step definitions](/docs/cucumber/step-definitions) and [hooks](/docs/cucumber/api/#hooks)) in plain old Java classes.
113+
{{% block "java,kotlin" %}} If your programming language is a JVM language, you will be writing glue code
114+
([step definitions](/docs/cucumber/step-definitions) and [hooks](/docs/cucumber/api/#hooks)) in classes.
102115

103116
Cucumber will create a new instance of each of your glue code classes before each scenario.
104117

@@ -112,10 +125,12 @@ The available dependency injection modules are:
112125
- [Guice](#guice)
113126
- [OpenEJB](#openejb)
114127
- [Weld](#weld)
115-
- [Needle](#needle)
128+
- [Needle](#needle)
116129

117-
### PicoContainer
130+
{{% /block %}} {{% block "ruby,javascript" %}} Dependency Injection is specific to JVM languages. {{% /block %}}
118131

132+
### PicoContainer
133+
{{% block "java,kotlin" %}}
119134
To use PicoContainer, add the following dependency to your `pom.xml`:
120135

121136
```xml
@@ -133,10 +148,14 @@ compile group: 'io.cucumber', name: 'cucumber-picocontainer', version: '{{% vers
133148
```
134149

135150
There is no documentation yet, but the code is on [GitHub](https://github.com/cucumber/cucumber-jvm/tree/master/picocontainer).
136-
For more information, please see [sharing state using Picocontainer](http://www.thinkcode.se/blog/2017/04/01/sharing-state-between-steps-in-cucumberjvm-using-picocontainer).
151+
For more information, please see [sharing state using PicoContainer](http://www.thinkcode.se/blog/2017/04/01/sharing-state-between-steps-in-cucumberjvm-using-picocontainer).
152+
{{% /block %}}
137153

138-
### Spring
154+
{{% block "ruby,javascript" %}} PicoContainer is a Dependency Injection framework for JVM languages. {{% /block %}}
139155

156+
157+
### Spring
158+
{{% block "java,kotlin" %}}
140159
To use Spring, add the following dependency to your `pom.xml`:
141160

142161
```xml
@@ -154,9 +173,12 @@ compile group: 'io.cucumber', name: 'cucumber-spring', version: '{{% version "cu
154173
```
155174

156175
There is no documentation yet, but the code is on [GitHub](https://github.com/cucumber/cucumber-jvm/tree/master/spring).
176+
{{% /block %}}
157177

158-
### Guice
178+
{{% block "ruby,javascript" %}} Spring is a Dependency Injection framework for JVM languages. {{% /block %}}
159179

180+
### Guice
181+
{{% block "java,kotlin" %}}
160182
To use Guice, add the following dependency to your `pom.xml`:
161183

162184
```xml
@@ -175,9 +197,12 @@ compile group: 'io.cucumber', name: 'cucumber-guice', version: '{{% version "cuc
175197

176198
There is no documentation yet, but the code is on [GitHub](https://github.com/cucumber/cucumber-jvm/tree/master/guice).
177199
For more information, please see [sharing state using Guice](http://www.thinkcode.se/blog/2017/08/16/sharing-state-between-steps-in-cucumberjvm-using-guice).
200+
{{% /block %}}
178201

179-
### OpenEJB
202+
{{% block "ruby,javascript" %}} Guice is a Dependency Injection framework for JVM languages. {{% /block %}}
180203

204+
### OpenEJB
205+
{{% block "java,kotlin" %}}
181206
To use OpenEJB, add the following dependency to your `pom.xml`:
182207

183208
```xml
@@ -195,9 +220,12 @@ compile group: 'io.cucumber', name: 'cucumber-openejb', version: '{{% version "c
195220
```
196221

197222
There is no documentation yet, but the code is on [GitHub](https://github.com/cucumber/cucumber-jvm/tree/master/openejb).
223+
{{% /block %}}
198224

199-
### Weld
225+
{{% block "ruby,javascript" %}} OpenEJB is a Dependency Injection framework for JVM languages. {{% /block %}}
200226

227+
### Weld
228+
{{% block "java,kotlin" %}}
201229
To use Weld, add the following dependency to your `pom.xml`:
202230

203231
```xml
@@ -215,9 +243,12 @@ compile group: 'io.cucumber', name: 'cucumber-weld', version: '{{% version "cucu
215243
```
216244

217245
There is no documentation yet, but the code is on [GitHub](https://github.com/cucumber/cucumber-jvm/tree/master/weld).
246+
{{% /block %}}
218247

219-
### Needle
248+
{{% block "ruby,javascript" %}} Weld is a Dependency Injection framework for JVM languages. {{% /block %}}
220249

250+
### Needle
251+
{{% block "java,kotlin" %}}
221252
To use Needle, add the following dependency to your `pom.xml`:
222253

223254
```xml
@@ -235,18 +266,22 @@ compile group: 'io.cucumber', name: 'cucumber-needle', version: '{{% version "cu
235266
```
236267

237268
There is no documentation yet, but the code is on [GitHub](https://github.com/cucumber/cucumber-jvm/tree/master/needle).
269+
{{% /block %}}
238270

239-
# How to use DI
271+
{{% block "ruby,javascript" %}} Needle is a Dependency Injection framework for JVM languages. {{% /block %}}
240272

273+
# How to use DI
274+
{{% block "java,kotlin" %}}
241275
When using a DI framework all your step definitions, hooks, transformers, etc. will be created by the frameworks instance injector.
276+
{{% /block %}}
242277

243-
## The need for a custom injector
278+
{{% block "ruby,javascript" %}} Dependency Injection is specific to JVM languages. {{% /block %}}
244279

245-
Cucumber example tests are typically small and have no dependencies.
246-
In real life, though, tests often need access to application specific object instances
247-
which also need to be supplied by the injector.
248-
These instances need to be made available to your step definitions so that actions
249-
can be applied on them and delivered results can be tested.
280+
## Using a custom injector
281+
{{% block "java,kotlin" %}} Cucumber example tests are typically small and have no dependencies. In real life, though,
282+
tests often need access to application specific object instances which also need to be supplied by the injector. These
283+
instances need to be made available to your step definitions so that actions can be applied on them and delivered
284+
results can be tested.
250285

251286
The reason using Cucumber with a DI framework typically originates from the fact that the tested application also uses
252287
the same framework. So we need to configure a custom injector to be used with Cucumber.
@@ -310,9 +345,12 @@ public final class ServiceModule extends AbstractModule {
310345
The actual injector is then created like this: `injector = Guice.createInjector( new ServiceModule() );`
311346

312347
This means we need to create our own injector and tell Cucumber to use it.
348+
{{% /block %}}
313349

314-
## The Cucumber object factory
350+
{{% block "ruby,javascript" %}} Using a custom injector is specific to JVM languages. {{% /block %}}
315351

352+
## The Cucumber object factory
353+
{{% block "java,kotlin" %}}
316354
Whenever Cucumber needs a specific object, it uses an object factory.
317355
Cucumber has a default object factory that (in case of Guice) creates a default injector and
318356
delegates object creation to that injector.
@@ -373,41 +411,51 @@ com.example.app.CustomObjectFactory
373411
```
374412

375413
Now we have to tell Cucumber to use our custom object factory. There are several ways how this could be accomplished.
414+
{{% /block %}}
376415

377-
### Using the command line
416+
{{% block "ruby,javascript" %}} The Cucumber object factory is specific to JVM languages. {{% /block %}}
378417

418+
### Using the Cucumber object factory from the command line
419+
{{% block "java,kotlin" %}}
379420
When Cucumber is run from the command line, the custom object factory can be specified as argument.
380421

381422
```bash
382423
java io.cucumber.core.cli.Main --object-factory com.example.app.CustomObjectFactory
383424
```
425+
{{% /block %}}
384426

385-
### Using the property file
427+
{{% block "ruby,javascript" %}} Using the Cucumber object factory is specific to JVM languages. {{% /block %}}
386428

387-
Cucumber makes use of a properties file (`cucumber.properties`) if it exists. The custom object factory can be
388-
specified in this file and will be picked up when Cucumber is running. The following entry needs to be available
389-
in the `cucumber.properties` file:
429+
### Using the Cucumber object factory a property file
430+
{{% block "java,kotlin" %}} Cucumber makes use of a properties file (`cucumber.properties`) if it exists. The custom
431+
object factory can be specified in this file and will be picked up when Cucumber is running. The following entry needs
432+
to be available in the `cucumber.properties` file:
390433

391434
```
392435
cucumber.object-factory=com.example.app.CustomObjectFactory
393436
```
437+
{{% /block %}}
394438

395-
### Using a test runner (JUnit/TestNG)
439+
{{% block "ruby,javascript" %}} Using the Cucumber object factory is specific to JVM languages. {{% /block %}}
396440

441+
### Using the Cucumber object factory a test runner (JUnit/TestNG)
442+
{{% block "java,kotlin" %}}
397443
The Cucumber modules for [JUnit](/docs/cucumber/api/#junit) and [TestNG](/docs/cucumber/checking-assertions/#testng) allow to run Cucumber through a JUnit/TestNG test.
398444
The custom object factory can be configured using the `@CucumberOptions` annotation.
445+
{{% /block %}}
446+
447+
{{% block "ruby,javascript" %}} Using the Cucumber object factory is specific to JVM languages. {{% /block %}}
399448

400449
# Databases
401450

402451
There are several options to remove state from your database, to prevent leaking state between scenarios.
403452

404453
## The Before Hook Approach
405454

406-
The recommended approach to clean a database between scenarios is to use a
407-
`Before` [hook](/docs/cucumber/api/#hooks) to remove all data *before* a scenario starts.
408-
409-
This is usually better than using an `After` [hook](/docs/cucumber/api/#hooks), as it allows
410-
you to perform a post-mortem inspection of the database if a scenario fails.
455+
The recommended approach to clean a database between scenarios is to use a `Before` [hook](/docs/cucumber/api/#hooks) to
456+
remove all data *before* a scenario starts. This is usually better than using an `After`
457+
[hook](/docs/cucumber/api/#hooks), as it allows you to perform a post-mortem inspection of the database if a scenario
458+
fails.
411459

412460
An alternative approach is to use database transactions.
413461

@@ -440,22 +488,27 @@ Feature: Let's write a lot of stuff to the DB
440488
```
441489

442490
### With JUnit and Spring
443-
491+
{{% block "java,kotlin" %}}
444492
See the [`spring-txn`](https://github.com/cucumber/cucumber-jvm/tree/master/examples/spring-txn) example in Cucumber-JVM for a minimal setup.
493+
{{% /block %}}
494+
495+
{{% block "ruby,javascript" %}} JUnit and Spring are used with JVM languages. {{% /block %}}
445496

446497
# Browser Automation and Transactions
447498

448-
If you're using a [browser automation](/docs/guides/browser-automation) tool that talks to your application over HTTP, the
449-
transactional approach will not work if your [step definitions](/docs/cucumber/step-definitions) and the web application serving
450-
HTTP request each have their own database connection.
451-
With transactions on, transactions are **never** committed to the database (but rolled back at the end of each Scenario).
452-
Therefore, the web server's connection will never see data from Cucumber, and therefore your browser won't either.
453-
Likewise, Cucumber's connection won't see data from the web server.
499+
If you're using a [browser automation](/docs/guides/browser-automation) tool that talks to your application over HTTP,
500+
the transactional approach will not work if your [step definitions](/docs/cucumber/step-definitions) and the web
501+
application serving HTTP request each have their own database connection. With transactions on, transactions are
502+
**never** committed to the database (but rolled back at the end of each Scenario). Therefore, the web server's
503+
connection will never see data from Cucumber, and therefore your browser won't either. Likewise, Cucumber's connection
504+
won't see data from the web server.
454505

455-
In this case, you will have to turn off database transactions and make sure the data is explicitly deleted before each Scenario.
506+
In this case, you will have to turn off database transactions and make sure the test data is explicitly deleted before each Scenario.
456507

457508
## Turn off transactions
458-
If you're using [Ruby on Rails](/docs/tools/ruby#ruby-on-rails), you can turn off transactions for a feature or particular scenarios. Use the `@no-txn` tag, like this:
509+
{{% block "ruby" %}}
510+
If you're using [Ruby on Rails](/docs/tools/ruby#ruby-on-rails), you can turn off transactions for
511+
a feature or particular scenarios. Use the `@no-txn` tag, like this:
459512

460513
```
461514
@no-txn
@@ -476,12 +529,14 @@ With Rails, you can also turn off transaction globally in your `features/support
476529
```
477530
Cucumber::Rails::World.use_transactional_fixtures = false
478531
```
532+
{{% /block %}}
479533

480-
## Cleaning Your Database
534+
{{% block "java,kotlin,javascript" %}} Ruby tools provide specific ways to turn of transactions. {{% /block %}}
481535

482-
If you're using [Ruby on Rails](/docs/tools/ruby#ruby-on-rails), a good tool to deal with this is Ben Mabey's
483-
[Database Cleaner](https://github.com/bmabey/database_cleaner) gem,
484-
which you can install with `gem install database_cleaner`.
536+
## Cleaning Your Database
537+
{{% block "ruby" %}} If you're using [Ruby on Rails](/docs/tools/ruby#ruby-on-rails), a good tool to deal with this is
538+
Ben Mabey's [Database Cleaner](https://github.com/bmabey/database_cleaner) gem, which you can install with `gem install
539+
database_cleaner`.
485540

486541
You can use this very effectively with the `@no-txn` tag. For example, add something like the following somewhere in e.g. `features/support/db_cleaner.rb`:
487542

@@ -525,3 +580,6 @@ After('@no-txn') do
525580
DatabaseCleaner.strategy = :transaction
526581
end
527582
```
583+
{{% /block %}}
584+
585+
{{% block "java,kotlin,javascript" %}} Ruby tools provide specific ways to clean your database. {{% /block %}}

0 commit comments

Comments
 (0)