package cucumber.runtime.java.guice.impl;
import com.google.inject.*;
import cucumber.api.guice.CucumberModules;
import cucumber.api.guice.CucumberScopes;
import cucumber.api.java.ObjectFactory;
import cucumber.runtime.java.guice.ScenarioScoped;
import org.junit.After;
import org.junit.Test;
import javax.inject.Singleton;
import java.util.Arrays;
import java.util.List;
import static cucumber.runtime.java.guice.matcher.ElementsAreAllEqualMatcher.elementsAreAllEqual;
import static cucumber.runtime.java.guice.matcher.ElementsAreAllUniqueMatcher.elementsAreAllUnique;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
public class GuiceFactoryTest {
private ObjectFactory factory;
private List<?> instancesFromSameScenario;
private List<?> instancesFromDifferentScenarios;
@After
public void tearDown() {
// If factory is left in start state it can cause cascading failures due to scope being left open
try { factory.stop(); } catch (Exception e) {}
}
@Test
public void factoryCanBeIntantiatedWithDefaultConstructor() throws Exception {
factory = new GuiceFactory();
assertThat(factory, notNullValue());
}
@Test
public void factoryCanBeIntantiatedWithArgConstructor() {
factory = new GuiceFactory(Guice.createInjector());
assertThat(factory, notNullValue());
}
@Test
public void factoryStartFailsIfScenarioScopeIsNotBound() {
factory = new GuiceFactory(Guice.createInjector());
try {
factory.start();
fail();
} catch (ConfigurationException e) {
assertThat(e.getMessage(),
containsString("No implementation for cucumber.runtime.java.guice.ScenarioScope was bound"));
}
}
static class UnscopedClass {}
@Test
public void shouldGiveNewInstancesOfUnscopedClassWithinAScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO));
instancesFromSameScenario = getInstancesFromSameScenario(factory, UnscopedClass.class);
assertThat(instancesFromSameScenario, elementsAreAllUnique());
}
@Test
public void shouldGiveNewInstanceOfUnscopedClassForEachScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO));
instancesFromDifferentScenarios = getInstancesFromDifferentScenarios(factory, UnscopedClass.class);
assertThat(instancesFromDifferentScenarios, elementsAreAllUnique());
}
@ScenarioScoped static class AnnotatedScenarioScopedClass {}
@Test
public void shouldGiveTheSameInstanceOfAnnotatedScenarioScopedClassWithinAScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO));
instancesFromSameScenario = getInstancesFromSameScenario(factory, AnnotatedScenarioScopedClass.class);
assertThat(instancesFromSameScenario, elementsAreAllEqual());
}
@Test
public void shouldGiveNewInstanceOfAnnotatedScenarioScopedClassForEachScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO));
instancesFromDifferentScenarios = getInstancesFromDifferentScenarios(factory, AnnotatedScenarioScopedClass.class);
assertThat(instancesFromDifferentScenarios, elementsAreAllUnique());
}
@Singleton static class AnnotatedSingletonClass {}
@Test
public void shouldGiveTheSameInstanceOfAnnotatedSingletonClassWithinAScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO));
instancesFromSameScenario = getInstancesFromSameScenario(factory, AnnotatedSingletonClass.class);
assertThat(instancesFromSameScenario, elementsAreAllEqual());
}
@Test
public void shouldGiveTheSameInstanceOfAnnotatedSingletonClassForEachScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO));
instancesFromDifferentScenarios = getInstancesFromDifferentScenarios(factory, AnnotatedSingletonClass.class);
assertThat(instancesFromDifferentScenarios, elementsAreAllEqual());
}
static class BoundScenarioScopedClass {}
final AbstractModule boundScenarioScopedClassModule = new AbstractModule() {
@Override protected void configure() {
bind(BoundScenarioScopedClass.class).in(CucumberScopes.SCENARIO);
}
};
@Test
public void shouldGiveTheSameInstanceOfBoundScenarioScopedClassWithinAScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO, boundScenarioScopedClassModule));
instancesFromSameScenario = getInstancesFromSameScenario(factory, BoundScenarioScopedClass.class);
assertThat(instancesFromSameScenario, elementsAreAllEqual());
}
@Test
public void shouldGiveNewInstanceOfBoundScenarioScopedClassForEachScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO, boundScenarioScopedClassModule));
instancesFromDifferentScenarios = getInstancesFromDifferentScenarios(factory, BoundScenarioScopedClass.class);
assertThat(instancesFromDifferentScenarios, elementsAreAllUnique());
}
static class BoundSingletonClass {}
final AbstractModule boundSingletonClassModule = new AbstractModule() {
@Override protected void configure() {
bind(BoundSingletonClass.class).in(Scopes.SINGLETON);
}
};
@Test
public void shouldGiveTheSameInstanceOfBoundSingletonClassWithinAScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO, boundSingletonClassModule));
instancesFromSameScenario = getInstancesFromSameScenario(factory, BoundSingletonClass.class);
assertThat(instancesFromSameScenario, elementsAreAllEqual());
}
@Test
public void shouldGiveTheSameInstanceOfBoundSingletonClassForEachScenario() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO, boundSingletonClassModule));
instancesFromDifferentScenarios = getInstancesFromDifferentScenarios(factory, BoundSingletonClass.class);
assertThat(instancesFromDifferentScenarios, elementsAreAllEqual());
}
@Test
public void shouldGiveNewInstanceOfAnnotatedSingletonClassForEachScenarioWhenOverridingModuleBindingIsScenarioScope() {
factory = new GuiceFactory(injector(CucumberModules.SCENARIO, new AbstractModule() {
@Override
protected void configure() {
bind(AnnotatedSingletonClass.class).in(CucumberScopes.SCENARIO);
}
}));
instancesFromDifferentScenarios = getInstancesFromDifferentScenarios(factory, AnnotatedSingletonClass.class);
assertThat(instancesFromDifferentScenarios, elementsAreAllUnique());
}
private Injector injector(Module... module) {
return Guice.createInjector(Stage.PRODUCTION, module);
}
private <E> List<E> getInstancesFromSameScenario(ObjectFactory factory, Class<E> aClass) {
// Scenario
factory.start();
E o1 = factory.getInstance(aClass);
E o2 = factory.getInstance(aClass);
E o3 = factory.getInstance(aClass);
factory.stop();
return Arrays.asList(o1, o2, o3);
}
private <E> List<E> getInstancesFromDifferentScenarios(ObjectFactory factory, Class<E> aClass) {
// Scenario 1
factory.start();
E o1 = factory.getInstance(aClass);
factory.stop();
// Scenario 2
factory.start();
E o2 = factory.getInstance(aClass);
factory.stop();
// Scenario 3
factory.start();
E o3 = factory.getInstance(aClass);
factory.stop();
return Arrays.asList(o1, o2, o3);
}
}