Skip to content

Commit 513090e

Browse files
committed
Closes issue cucumber#448. Implementation based on SpringJunit4ClassRunner and still trying to stick to the previous behaviour as much as possible
1 parent 22d192c commit 513090e

File tree

9 files changed

+184
-92
lines changed

9 files changed

+184
-92
lines changed

spring/pom.xml

+20
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,27 @@
3737
<artifactId>spring-context-support</artifactId>
3838
<scope>provided</scope>
3939
</dependency>
40+
<dependency>
41+
<groupId>org.springframework</groupId>
42+
<artifactId>spring-test</artifactId>
43+
<scope>provided</scope>
44+
</dependency>
4045

46+
<dependency>
47+
<groupId>org.springframework</groupId>
48+
<artifactId>spring-web</artifactId>
49+
<scope>test</scope>
50+
</dependency>
51+
<dependency>
52+
<groupId>org.springframework</groupId>
53+
<artifactId>spring-webmvc</artifactId>
54+
<scope>test</scope>
55+
</dependency>
56+
<dependency>
57+
<groupId>javax.servlet</groupId>
58+
<artifactId>javax.servlet-api</artifactId>
59+
<scope>test</scope>
60+
</dependency>
4161
<dependency>
4262
<groupId>info.cukes</groupId>
4363
<artifactId>cucumber-junit</artifactId>
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package cucumber.runtime.java.spring;
22

3-
import cucumber.runtime.CucumberException;
4-
import cucumber.runtime.java.ObjectFactory;
5-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3+
import java.util.Collection;
4+
import java.util.HashSet;
5+
66
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
77
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
8-
import org.springframework.context.support.AbstractApplicationContext;
9-
import org.springframework.context.support.ClassPathXmlApplicationContext;
8+
import org.springframework.context.ConfigurableApplicationContext;
9+
import org.springframework.context.support.GenericXmlApplicationContext;
10+
import org.springframework.test.context.TestContextManager;
1011

11-
import java.util.Collection;
12-
import java.util.HashSet;
12+
import cucumber.runtime.CucumberException;
13+
import cucumber.runtime.java.ObjectFactory;
1314

1415
/**
1516
* Spring based implementation of ObjectFactory.
@@ -31,52 +32,66 @@
3132
*/
3233
public class SpringFactory implements ObjectFactory {
3334

34-
private static AbstractApplicationContext applicationContext;
35-
36-
private final Collection<Class<?>> stepClasses = new HashSet<Class<?>>();
37-
38-
public SpringFactory() {
39-
}
40-
41-
static {
42-
applicationContext = new ClassPathXmlApplicationContext(
43-
"cucumber/runtime/java/spring/cucumber-glue.xml",
44-
"cucumber.xml");
45-
applicationContext.registerShutdownHook();
46-
}
47-
48-
@Override
49-
public void addClass(final Class<?> stepClass) {
50-
if (!stepClasses.contains(stepClass)) {
51-
stepClasses.add(stepClass);
52-
53-
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
54-
registry.registerBeanDefinition(stepClass.getName(),
55-
BeanDefinitionBuilder.genericBeanDefinition(stepClass)
56-
.setScope(GlueCodeScope.NAME)
57-
.getBeanDefinition());
58-
59-
}
60-
}
61-
62-
@Override
63-
public void start() {
64-
GlueCodeContext.INSTANCE.start();
65-
}
66-
67-
@Override
68-
public void stop() {
69-
GlueCodeContext.INSTANCE.stop();
70-
}
71-
72-
@SuppressWarnings("unchecked")
73-
@Override
74-
public <T> T getInstance(final Class<T> type) {
75-
try {
76-
return applicationContext.getBean(type);
77-
} catch (NoSuchBeanDefinitionException exception) {
78-
throw new CucumberException(exception.getMessage(), exception);
79-
}
80-
}
35+
private static ConfigurableApplicationContext applicationContext;
36+
37+
private final Collection<Class<?>> stepClasses = new HashSet<Class<?>>();
38+
39+
public SpringFactory() {
40+
}
41+
42+
static {
43+
applicationContext = new GenericXmlApplicationContext(
44+
"cucumber/runtime/java/spring/cucumber-glue.xml");
45+
applicationContext.registerShutdownHook();
46+
}
47+
48+
@Override
49+
public void addClass(final Class<?> stepClass) {
50+
if (!stepClasses.contains(stepClass)) {
51+
stepClasses.add(stepClass);
52+
53+
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext
54+
.getAutowireCapableBeanFactory();
55+
registry.registerBeanDefinition(stepClass.getName(),
56+
BeanDefinitionBuilder.genericBeanDefinition(stepClass)
57+
.setScope(GlueCodeScope.NAME).getBeanDefinition());
58+
59+
}
60+
}
61+
62+
@Override
63+
public void start() {
64+
GlueCodeContext.INSTANCE.start();
65+
}
66+
67+
@Override
68+
public void stop() {
69+
GlueCodeContext.INSTANCE.stop();
70+
applicationContext.getBeanFactory().destroySingletons();
71+
}
72+
73+
@SuppressWarnings("unchecked")
74+
@Override
75+
public <T> T getInstance(final Class<T> type) {
76+
T instance = null;
77+
if (!applicationContext.getBeanFactory().containsSingleton(type.getName())) {
78+
try{
79+
instance = createTest(type);
80+
TestContextManager contextManager = new TestContextManager(type);
81+
contextManager.prepareTestInstance(instance);
82+
} catch (Exception e) {
83+
new CucumberException(e.getMessage(), e);
84+
}
85+
applicationContext.getBeanFactory().registerSingleton(type.getName(), instance);
86+
} else {
87+
instance = applicationContext.getBean(type);
88+
}
89+
return instance;
90+
}
91+
92+
@SuppressWarnings("unchecked")
93+
protected <T> T createTest(Class<T> type) throws Exception {
94+
return (T) type.getConstructors()[0].newInstance();
95+
}
8196

8297
}

spring/src/test/java/cucumber/runtime/java/spring/BellyStepdefs.java

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
package cucumber.runtime.java.spring;
22

3-
import cucumber.api.java.en.Given;
4-
import cucumber.api.java.en.Then;
3+
import static org.junit.Assert.assertEquals;
4+
55
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.test.context.ContextConfiguration;
67

7-
import static org.junit.Assert.assertEquals;
8+
import cucumber.api.java.en.Given;
9+
import cucumber.api.java.en.Then;
810

11+
@ContextConfiguration("classpath:cucumber.xml")
912
public class BellyStepdefs {
10-
private final Belly belly;
13+
14+
@Autowired
15+
private Belly belly;
1116

1217
@Autowired
1318
private BellyBean bellyBean;
14-
15-
@Autowired
16-
public BellyStepdefs(final Belly belly) {
17-
this.belly = belly;
18-
}
19-
19+
2020
@Then("^there are (\\d+) cukes in my belly")
2121
public void checkCukes(final int n) {
2222
assertEquals(n, belly.getCukes());
@@ -36,4 +36,9 @@ public void I_have_beans_in_my_belly(int n) {
3636
public void there_are_beans_in_my_belly(int n) {
3737
assertEquals(n, bellyBean.getCukes());
3838
}
39+
40+
public BellyBean getBellyBean() {
41+
return bellyBean;
42+
}
43+
3944
}

spring/src/test/java/cucumber/runtime/java/spring/SpringFactoryTest.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package cucumber.runtime.java.spring;
22

3-
import cucumber.runtime.java.ObjectFactory;
4-
import org.junit.Test;
5-
63
import static org.junit.Assert.assertEquals;
74
import static org.junit.Assert.assertNotNull;
85
import static org.junit.Assert.assertNotSame;
96
import static org.junit.Assert.assertSame;
107
import static org.junit.Assert.assertTrue;
118

9+
import org.junit.Test;
10+
11+
import cucumber.runtime.java.ObjectFactory;
12+
1213
public class SpringFactoryTest {
1314

1415
@Test
@@ -36,13 +37,13 @@ public void shouldNeverCreateNewApplicationBeanInstances() {
3637
// Feature 1
3738
final ObjectFactory factory1 = new SpringFactory();
3839
factory1.start();
39-
final DummyComponent o1 = factory1.getInstance(DummyComponent.class);
40+
final BellyBean o1 = factory1.getInstance(BellyStepdefs.class).getBellyBean();
4041
factory1.stop();
4142

4243
// Feature 2
4344
final ObjectFactory factory2 = new SpringFactory();
4445
factory2.start();
45-
final DummyComponent o2 = factory2.getInstance(DummyComponent.class);
46+
final BellyBean o2 = factory2.getInstance(BellyStepdefs.class).getBellyBean();
4647
factory2.stop();
4748

4849
assertNotNull(o1);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package cucumber.runtime.java.spring;
2+
3+
import static org.junit.Assert.assertNotNull;
4+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
5+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
6+
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.test.context.ContextConfiguration;
9+
import org.springframework.test.context.web.WebAppConfiguration;
10+
import org.springframework.test.web.servlet.MockMvc;
11+
import org.springframework.test.web.servlet.ResultActions;
12+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
13+
import org.springframework.web.context.WebApplicationContext;
14+
15+
import cucumber.api.java.en.Given;
16+
import cucumber.api.java.en.Then;
17+
import cucumber.api.java.en.When;
18+
19+
@WebAppConfiguration
20+
@ContextConfiguration("classpath:cucumber.xml")
21+
public class SpringInjectionStepDefs {
22+
23+
@Autowired
24+
private WebApplicationContext wac;
25+
26+
private ResultActions callUrl;
27+
28+
@Given("^I have the web context set$")
29+
public void I_have_the_web_context_set() throws Throwable {
30+
assertNotNull(wac);
31+
}
32+
33+
@When("^I call the url \"([^\"]*)\"$")
34+
public void I_call_the_url(String url) throws Throwable {
35+
MockMvc mock = MockMvcBuilders.webAppContextSetup(wac).build();
36+
callUrl = mock.perform(get(url));
37+
}
38+
39+
@Then("^it should return (\\d+)$")
40+
public void it_should_return(int httpCode) throws Throwable {
41+
callUrl.andExpect(status().is(httpCode));
42+
}
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package cucumber.runtime.java.spring;
2+
3+
import org.springframework.stereotype.Component;
4+
import org.springframework.web.bind.annotation.RequestMapping;
5+
import org.springframework.web.bind.annotation.RequestMethod;
6+
import org.springframework.web.bind.annotation.ResponseBody;
7+
8+
@Component
9+
@RequestMapping(TestController.BASE_URL)
10+
public class TestController {
11+
12+
public static final String BASE_URL = "/test";
13+
14+
@ResponseBody
15+
@RequestMapping(method=RequestMethod.GET)
16+
public String test() {
17+
return "ok";
18+
}
19+
20+
}

spring/src/test/java/cucumber/runtime/java/spring/WithSpringAnnotations.java

+2-23
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,16 @@
22

33
import org.springframework.beans.factory.annotation.Autowired;
44
import org.springframework.beans.factory.annotation.Value;
5+
import org.springframework.test.context.ContextConfiguration;
56

6-
import javax.annotation.PostConstruct;
7-
import javax.annotation.PreDestroy;
8-
7+
@ContextConfiguration("classpath:cucumber.xml")
98
public class WithSpringAnnotations {
109

11-
private boolean preDestroyCalled;
12-
private boolean postConstructCalled;
1310
private boolean autowired;
1411

1512
@Value("${cukes.test.property}")
1613
private String property;
1714

18-
@PostConstruct
19-
public void postConstruct() {
20-
postConstructCalled = true;
21-
}
22-
23-
@PreDestroy
24-
public void preDestroy() {
25-
preDestroyCalled = true;
26-
}
27-
2815
@Autowired
2916
public void setAutowiredCollaborator(DummyComponent collaborator) {
3017
autowired = true;
@@ -34,14 +21,6 @@ public boolean isAutowired() {
3421
return autowired;
3522
}
3623

37-
public boolean isPostConstructCalled() {
38-
return postConstructCalled;
39-
}
40-
41-
public boolean isPreDestroyCalled() {
42-
return preDestroyCalled;
43-
}
44-
4524
public String getProperty() {
4625
return property;
4726
}

spring/src/test/resources/applicationContext.xml

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
<bean id="bellyBean" class="cucumber.runtime.java.spring.BellyBean"/>
77

8+
<bean id="testController" class="cucumber.runtime.java.spring.TestController"/>
9+
810
<bean id="placeholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
911
<property name="properties">
1012
<props>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Feature: Spring injection with annotations
2+
3+
Scenario: Inject web context
4+
Given I have the web context set
5+
When I call the url "/test"
6+
Then it should return 200

0 commit comments

Comments
 (0)