|
3 | 3 | This module allows you to use Google Guice dependency injection in your Cucumber tests. Guice comes as standard with
|
4 | 4 | singleton scope and 'no scope'. This module adds Cucumber scenario scope to the scopes available for use in your
|
5 | 5 | test code. The rest of this documentation assumes you have at least a basic understanding of Guice. Please refer to
|
6 |
| - the Google documentation if necessary, see https://code.google.com/p/google-guice/wiki/Motivation?tm=6 |
7 |
| - |
8 |
| - <b>About scopes, injectors and migration from earlier versions</b> |
9 |
| - |
| 6 | + the Guice wiki if necessary, see <a href="https://github.com/google/guice/wiki/Motivation" |
| 7 | + target="_parent"> |
| 8 | + https://github.com/google/guice/wiki/Motivation</a> |
| 9 | +</p> |
| 10 | + <h3>About scopes, injectors and migration from earlier versions</h3> |
| 11 | +<p> |
10 | 12 | It's important to realise the differences in how this module functions when compared with earlier versions. The
|
11 | 13 | changes are as follows.
|
12 |
| - |
13 |
| - <= 1.1.7 A Guice injector is created at the start of each test scenario and is destroyed at the end of each test |
14 |
| - scenario. There is no scenario scope, just singleton and 'no scope'. |
15 |
| - |
16 |
| - > 1.1.7 A Guice injector is created once before any tests are run and is destroyed after the last test has run. |
17 |
| - Before each test scenario a new scenario scope is created. At the end of the test scenario the scenario |
18 |
| - scope is destroyed. Singleton scope exists throughout all test scenarios. |
19 |
| - |
20 |
| - Users wishing to migrate to this version should replace <code>@Singleton</code> annotations with |
21 |
| - <code>@ScenarioScope</code> annotations. Guice modules should also have their singleton bindings updated. All |
22 |
| - bindings in <code>Scopes.SINGLETON</code> should be replaced with bindings in <code>CucumberScopes.SCENARIO</code>. |
23 |
| - |
24 |
| - <b>Using the module</b> |
25 |
| - |
| 14 | +</p> |
| 15 | + <h4>Version 1.1.7 and earlier</h4> |
| 16 | +<p> |
| 17 | + A Guice injector is created at the start of each test scenario and is destroyed at the end of each test scenario. |
| 18 | + There is no scenario scope, just singleton and 'no scope'. |
| 19 | +</p> |
| 20 | + <h4>Version 1.1.8 onwards</h4> |
| 21 | +<p> |
| 22 | + A Guice injector is created once before any tests are run and is destroyed after the last test has run. Before each |
| 23 | + test scenario a new scenario scope is created. At the end of the test scenario the scenario scope is destroyed. |
| 24 | + Singleton scope exists throughout all test scenarios. |
| 25 | +</p> |
| 26 | + <h4>Migrating to version 1.1.8 or later</h4> |
| 27 | +<p> |
| 28 | + Users wishing to migrate should replace <code>@Singleton</code> annotations with <code>@ScenarioScope</code> |
| 29 | + annotations. Guice modules should also have their singleton bindings updated. All bindings in |
| 30 | + <code>Scopes.SINGLETON</code> should be replaced with bindings in <code>CucumberScopes.SCENARIO</code>. |
| 31 | +</p> |
| 32 | + <h3>Using the module</h3> |
| 33 | +<p> |
26 | 34 | By including the <code>cucumber-guice</code> jar on your <code>CLASSPATH</code> your Step Definitions will be
|
27 | 35 | instantiated by Guice. There are two main modes of using the module: with scope annotations and with module
|
28 | 36 | bindings. The two modes can also be mixed. When mixing modes it is important to realise that binding a class in a
|
29 | 37 | scope in a module takes precedence if the same class is also bound using a scope annotation.
|
30 |
| - |
31 |
| - <b>Scoping your step definitions</b> |
32 |
| - |
| 38 | +</p> |
| 39 | + <h3>Scoping your step definitions</h3> |
| 40 | +<p> |
33 | 41 | Usually you will want to bind your step definition classes in either scenario scope or in singleton scope. It is not
|
34 | 42 | recommended to leave your step definition classes with no scope as it means that Cucumber will instantiate a new
|
35 | 43 | instance of the class for each step within a scenario that uses that step definition.
|
36 |
| - |
37 |
| - <b>Scenario scope</b> |
38 |
| - |
| 44 | +</p> |
| 45 | + <h3>Scenario scope</h3> |
| 46 | +<p> |
39 | 47 | Cucumber will create exactly one instance of a class bound in scenario scope for each scenario in which it is used.
|
40 | 48 | You should use scenario scope when you want to store state during a scenario but do not want the state to interfere
|
41 | 49 | with subsequent scenarios.
|
42 |
| - |
43 |
| - <b>Singleton scope</b> |
44 |
| - |
| 50 | +</p> |
| 51 | +<p> |
| 52 | + <h3>Singleton scope</h3> |
| 53 | +<p> |
45 | 54 | Cucumber will create just one instance of a class bound in singleton scope that will last for the lifetime of all
|
46 | 55 | test scenarios in the test run. You should use singleton scope if your classes are stateless. You can also use
|
47 | 56 | singleton scope when your classes contain state but with caution. You should be absolutely sure that a state change
|
48 | 57 | in one scenario could not possibly influence the success or failure of a subsequent scenario. As an example of when
|
49 | 58 | you might use a singleton, imagine you have an http client that is expensive to create. By holding a reference to
|
50 | 59 | the client in a class bound in singleton scope you can reuse the client in multiple scenarios.
|
51 |
| - |
52 |
| - <b>Using scope annotations</b> |
53 |
| - |
| 60 | +</p> |
| 61 | + <h3>Using scope annotations</h3> |
| 62 | +<p> |
54 | 63 | This is the easy route if you're new to Guice. To bind a class in scenario scope add the
|
55 | 64 | <code>cucumber.runtime.java.guice.ScenarioScoped</code> annotation to the class definition. The class should have
|
56 | 65 | a no-args constructor or one constructor that is annotated with <code>javax.inject.Inject</code>. For example:
|
57 |
| - |
58 |
| - <code> |
| 66 | +</p> |
| 67 | + <pre> |
59 | 68 | import cucumber.runtime.java.guice.ScenarioScoped;
|
60 | 69 | import javax.inject.Inject;
|
61 | 70 |
|
62 |
| - @ScenarioScoped |
| 71 | + {@literal @}ScenarioScoped |
63 | 72 | public class ScenarioScopedSteps {
|
64 | 73 |
|
65 | 74 | private final Object someInjectedDependency;
|
66 | 75 |
|
67 |
| - @Inject |
| 76 | + {@literal @}Inject |
68 | 77 | public ScenarioScopedSteps(Object someInjectedDependency) {
|
69 | 78 | this.someInjectedDependency = someInjectedDependency;
|
70 | 79 | }
|
71 | 80 |
|
72 | 81 | ...
|
73 | 82 | }
|
74 |
| - </code> |
75 |
| - |
| 83 | + </pre> |
| 84 | +<p> |
76 | 85 | To bind a class in singleton scope add the <code>javax.inject.Singleton</code> annotation to the class definition.
|
77 | 86 | One strategy for using stateless step definitions is to use providers to share stateful scenario scoped instances
|
78 | 87 | between stateless singleton step definition instances. For example:
|
79 |
| - |
80 |
| - <code> |
| 88 | +</p> |
| 89 | + <pre> |
81 | 90 | import javax.inject.Inject;
|
82 | 91 | import javax.inject.Singleton;
|
83 | 92 |
|
84 |
| - @Singleton |
| 93 | + {@literal @}Singleton |
85 | 94 | public class MyStatelessSteps {
|
86 | 95 |
|
87 | 96 | private final Provider<MyStatefulObject> providerMyStatefulObject;
|
88 | 97 |
|
89 |
| - @Inject |
| 98 | + {@literal @}Inject |
90 | 99 | public MyStatelessSteps(Provider<MyStatefulObject> providerMyStatefulObject) {
|
91 | 100 | this.providerMyStatefulObject = providerMyStatefulObject;
|
92 | 101 | }
|
93 | 102 |
|
94 |
| - @Given("^I have (\\d+) cukes in my belly$") |
| 103 | + {@literal @}Given("^I have (\\d+) cukes in my belly$") |
95 | 104 | public void I_have_cukes_in_my_belly(int n) {
|
96 | 105 | providerMyStatefulObject.get().iHaveCukesInMyBelly(n);
|
97 | 106 | }
|
98 | 107 |
|
99 | 108 | ...
|
100 | 109 | }
|
101 |
| - </code> |
102 |
| - |
103 |
| - See https://code.google.com/p/google-guice/wiki/InjectingProviders "Providers for Mixing Scopes" |
104 |
| - |
105 |
| - <b>Using module bindings</b> |
106 |
| - |
| 110 | + </pre> |
| 111 | +<p> |
| 112 | + There is an alternative explanation of using |
| 113 | + <a href="https://github.com/google/guice/wiki/InjectingProviders#providers-for-mixing-scopes" target="_parent"> |
| 114 | + providers for mixing scopes</a> on the Guice wiki. |
| 115 | +</p> |
| 116 | + <h3>Using module bindings</h3> |
| 117 | +<p> |
107 | 118 | As an alternative to using annotations you may prefer to declare Guice bindings in a class that implements
|
108 | 119 | <code>com.google.inject.Module</code>. To do this you should create a class that implements
|
109 | 120 | <code>cucumber.runtime.java.guice.InjectorSource</code>. This gives you complete control over how you obtain a
|
110 | 121 | Guice injector and it's Guice modules. The injector must provide a binding for
|
111 | 122 | <code>cucumber.runtime.java.guice.ScenarioScope</code>. It should also provide a binding for the
|
112 | 123 | <code>cucumber.runtime.java.guice.ScenarioScoped</code> annotation if your classes are using the annotation. The
|
113 | 124 | easiest way to do this it to use <code>CucumberModules.SCENARIO</code>. For example:
|
114 |
| - |
115 |
| - <code> |
| 125 | +</p> |
| 126 | + <pre> |
116 | 127 | import com.google.inject.Guice;
|
117 | 128 | import com.google.inject.Injector;
|
118 | 129 | import com.google.inject.Stage;
|
|
121 | 132 |
|
122 | 133 | public class YourInjectorSource implements InjectorSource {
|
123 | 134 |
|
124 |
| - @Override |
| 135 | + {@literal @}Override |
125 | 136 | public Injector getInjector() {
|
126 | 137 | return Guice.createInjector(Stage.PRODUCTION, CucumberModules.SCENARIO, new YourModule());
|
127 | 138 | }
|
128 | 139 | }
|
129 |
| - </code> |
130 |
| - |
| 140 | + </pre> |
| 141 | +<p> |
131 | 142 | Cucumber needs to know where to find the <code>cucumber.runtime.java.guice.InjectorSource</code> that it will use.
|
132 | 143 | You should create a properties file called <code>cucumber-guice.properties</code> and place it in the root of the
|
133 | 144 | classpath. The file should contain a single property key called <code>guice.injector-source</code> with a value
|
134 | 145 | equal to the fully qualified name of the <code>cucumber.runtime.java.guice.InjectorSource</code>. For example:
|
135 |
| - |
136 |
| - <code> |
137 |
| - guice.injector-source=com.company.YourInjectorSource |
138 |
| - </code> |
139 |
| - |
140 | 146 | </p>
|
| 147 | + <pre> |
| 148 | + guice.injector-source=com.company.YourInjectorSource |
| 149 | + </pre> |
141 | 150 | </body>
|
0 commit comments