/guice/src/main/java/cucumber/api/guice/package.html

https://gitlab.com/chiavegatto/cucumber-jvm · HTML · 150 lines · 139 code · 11 blank · 0 comment · 0 complexity · f36cf4cd07349bdd9fbedc2512a6df56 MD5 · raw file

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