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