package org.jbehave.core.steps.spring;
import java.util.List;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.steps.CandidateSteps;
import org.jbehave.core.steps.Steps;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class SpringStepsFactoryBehaviour {
@Test
public void stepsCanBeCreated() {
// Given
ApplicationContext context = createApplicationContext("org/jbehave/core/steps/spring/steps.xml");
SpringStepsFactory factory = new SpringStepsFactory(
new MostUsefulConfiguration(), context);
// When
List<CandidateSteps> steps = factory.createCandidateSteps();
// Then
assertFooStepsFound(steps);
}
@Test
public void annotationStepsCanBeCreated() throws Exception {
// Given
ApplicationContext context = createApplicationContext(StepsAnnotationConfiguration.class
.getName());
SpringStepsFactory factory = new SpringStepsFactory(
new MostUsefulConfiguration(), context);
// When
List<CandidateSteps> steps = factory.createCandidateSteps();
// Then
assertFooStepsFound(steps);
}
@Test
public void stepsWithDependenciesCanBeCreated() {
// Given
ApplicationContext context = createApplicationContext("org/jbehave/core/steps/spring/steps-with-dependency.xml");
// When
SpringStepsFactory factory = new SpringStepsFactory(
new MostUsefulConfiguration(), context);
List<CandidateSteps> steps = factory.createCandidateSteps();
// Then
assertFooStepsFound(steps);
assertEquals(
42,
(int) findInstanceOfType(steps, FooStepsWithDependency.class).integer);
}
@Test
public void annotationStepsWithDependenciesCanBeCreated() {
// Given
ApplicationContext context = createApplicationContext(StepsWithDependencyAnnotationConfiguration.class
.getName());
// When
SpringStepsFactory factory = new SpringStepsFactory(
new MostUsefulConfiguration(), context);
List<CandidateSteps> steps = factory.createCandidateSteps();
// Then
assertFooStepsFound(steps);
assertEquals(
42,
(int) findInstanceOfType(steps, FooStepsWithDependency.class).integer);
}
private void assertFooStepsFound(List<CandidateSteps> steps) {
assertEquals(1, steps.size());
assertThat(firstStepsInstance(steps), instanceOf(FooSteps.class));
}
private Object firstStepsInstance(List<CandidateSteps> steps) {
return ((Steps) steps.get(0)).instance();
}
private <T> T findInstanceOfType(List<CandidateSteps> steps, Class<T> type) {
for (CandidateSteps candidates : steps) {
Object instance = ((Steps) candidates).instance();
if (instance.getClass().equals(type)) {
return type.cast(instance);
}
}
throw new RuntimeException("Could not find type " + type + " amongst "
+ steps);
}
@Test(expected = BeanDefinitionStoreException.class)
public void stepsWithMissingDependenciesCannotBeCreated() {
// Given
ApplicationContext context = createApplicationContext("org/jbehave/core/steps/spring/steps-with-missing-depedency.xml");
SpringStepsFactory factory = new SpringStepsFactory(
new MostUsefulConfiguration(), context);
// When
factory.createCandidateSteps();
// Then ... expected exception is thrown
}
@Test
public void beansWithUndefinedTypeOrCannotBeCreatedWillBeIgnored() {
// Given
ApplicationContext context = mock(ApplicationContext.class);
SpringStepsFactory factory = new SpringStepsFactory(
new MostUsefulConfiguration(), context);
// When
when(context.getBeanDefinitionNames()).thenReturn(
new String[] { "fooSteps", "undefined", "blowUp" });
doAnswer(new Answer<Class<FooSteps>>() {
public Class<FooSteps> answer(InvocationOnMock invocation)
throws Throwable {
return FooSteps.class;
}
}).when(context).getType("fooSteps");
when(context.getType("undefined")).thenReturn(null);
doAnswer(new Answer<Class<BlowUp>>() {
public Class<BlowUp> answer(InvocationOnMock invocation)
throws Throwable {
return BlowUp.class;
}
}).when(context).getType("blowUp");
when(context.getBean("fooSteps")).thenReturn(new FooSteps());
when(context.getBean("blowUp")).thenThrow(new RuntimeException("Bum!"));
List<CandidateSteps> candidateSteps = factory.createCandidateSteps();
// Then
assertThat(candidateSteps.size(), equalTo(1));
assertThat(firstStepsInstance(candidateSteps),
instanceOf(FooSteps.class));
verify(context, never()).getBean("undefined");
}
private ApplicationContext createApplicationContext(String... resources) {
return new SpringApplicationContextFactory(resources)
.createApplicationContext();
}
public static class FooSteps {
@Given("a step with a $param")
public void aStepWithAParam(String param) {
}
}
public static class FooStepsWithDependency extends FooSteps {
private final Integer integer;
public FooStepsWithDependency(Integer integer) {
this.integer = integer;
}
}
public static abstract class AbstractSteps {
}
public static class BlowUp {
}
@Configuration
public static class StepsAnnotationConfiguration {
@Bean
public SpringStepsFactoryBehaviour.FooSteps fooSteps() {
return new SpringStepsFactoryBehaviour.FooSteps();
}
}
@Configuration
public static class StepsWithDependencyAnnotationConfiguration {
@Bean
public SpringStepsFactoryBehaviour.FooStepsWithDependency fooSteps() {
return new SpringStepsFactoryBehaviour.FooStepsWithDependency(42);
}
}
}