Support Groovy scripts in the TCF

Spring Framework 4.0 introduced first-class support for a Groovy-based
DSL for defining the beans for an ApplicationContext. However, prior to
this commit, the Spring TestContext Framework (TCF) did not provide any
out-of-the-box support for using Groovy scripts as path-based resource
locations when loading an application context for tests.

This commit addresses this issue by introducing first-class support for
using Groovy scripts to load the ApplicationContext for integration
tests managed by the TCF. Specifically, the following changes have been
made in the TCF to support Groovy scripts.

 - Introduced getResourceSuffixes() in AbstractContextLoader in order
   to support multiple resource suffixes in the default detection
   process. This feature is used by the new Groovy/Xml context loaders.

 - Introduced GenericGroovyXmlContextLoader and
   GenericGroovyXmlWebContextLoader which support both Groovy scripts
   and XML config files for loading bean definitions. Furthermore,
   these loaders support "-context.xml" and "Context.groovy" as
   resource suffixes when detecting defaults. Note that a default XML
   config file will be detected before a default Groovy script.

 - DelegatingSmartContextLoader and WebDelegatingSmartContextLoader now
   use reflection to choose between using GenericGroovyXmlContextLoader
   and GenericGroovyXmlWebContextLoader vs. GenericXmlContextLoader and
   GenericXmlWebContextLoader as their XML loaders, depending on
   whether Groovy is present in the classpath.

 - Groovy scripts can be configured via the 'locations' or 'value'
   attributes of @ContextConfiguration and can be mixed seamlessly with
   XML config files.

Issue: SPR-11233
This commit is contained in:
Sam Brannen
2014-07-21 23:29:05 +02:00
parent d4fe732f46
commit 35c372f200
28 changed files with 1011 additions and 111 deletions

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy;
import org.springframework.test.context.ContextConfiguration;
/**
* Extension of {@link GroovySpringContextTests} that declares a Groovy
* script using an absolute path.
*
* @author Sam Brannen
* @since 4.1
* @see GroovySpringContextTests
* @see RelativePathGroovySpringContextTests
*/
@ContextConfiguration(locations = "/org/springframework/test/context/groovy/context.groovy", inheritLocations = false)
public class AbsolutePathGroovySpringContextTests extends GroovySpringContextTests {
/* all tests are in the superclass */
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.tests.sample.beans.Employee;
import org.springframework.tests.sample.beans.Pet;
import static org.junit.Assert.*;
/**
* Integration test class that verifies proper detection of a default
* Groovy script (as opposed to a default XML config file).
*
* @author Sam Brannen
* @since 4.1
* @see DefaultScriptDetectionGroovySpringContextTestsContext
*/
@RunWith(SpringJUnit4ClassRunner.class)
// Config loaded from DefaultScriptDetectionGroovySpringContextTestsContext.groovy
@ContextConfiguration
public class DefaultScriptDetectionGroovySpringContextTests {
@Autowired
private Employee employee;
@Autowired
private Pet pet;
@Autowired
protected String foo;
@Test
public final void verifyAnnotationAutowiredFields() {
assertNotNull("The employee field should have been autowired.", this.employee);
assertEquals("Dilbert", this.employee.getName());
assertNotNull("The pet field should have been autowired.", this.pet);
assertEquals("Dogbert", this.pet.getName());
assertEquals("The foo field should have been autowired.", "Foo", this.foo);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy
import org.springframework.tests.sample.beans.Employee;
import org.springframework.tests.sample.beans.Pet;
/**
* Groovy script for defining Spring beans for integration tests.
*
* @author Sam Brannen
* @since 4.1
*/
beans {
foo String, 'Foo'
bar String, 'Bar'
employee(Employee) {
name = "Dilbert"
age = 42
company = "???"
}
pet(Pet, 'Dogbert')
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="foo" class="java.lang.String">
<constructor-arg value="Foo" />
</bean>
</beans>

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
/**
* Integration test class that verifies proper detection of a default
* XML config file even though a suitable Groovy script exists.
*
* @author Sam Brannen
* @since 4.1
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class DefaultScriptDetectionXmlSupersedesGroovySpringContextTests {
@Autowired
protected String foo;
@Test
public final void foo() {
assertEquals("The foo field should have been autowired.", "Foo", this.foo);
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy
/**
* This is intentionally an empty config file, since the XML file should
* be picked up as the default before a Groovy script.
*
* <p>See: {@code DefaultScriptDetectionXmlSupersedesGroovySpringContextTests-context.xml}
*
* @author Sam Brannen
* @since 4.1
*/
beans {
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericGroovyApplicationContext;
import org.springframework.tests.sample.beans.Employee;
import org.springframework.tests.sample.beans.Pet;
import static org.junit.Assert.*;
/**
* Simple integration test to verify the expected functionality of
* {@link GenericGroovyApplicationContext}, thereby validating the proper
* syntax and configuration of {@code "context.groovy"} without using the
* Spring TestContext Framework.
*
* <p>In other words, this test class serves merely as a <em>control group</em>
* to ensure that there is nothing wrong with the Groovy script used by
* other tests in this package.
*
* @author Sam Brannen
* @since 4.1
*/
public class GroovyControlGroupTests {
@Test
@SuppressWarnings("resource")
public void verifyScriptUsingGenericGroovyApplicationContext() {
ApplicationContext ctx = new GenericGroovyApplicationContext(getClass(), "context.groovy");
String foo = ctx.getBean("foo", String.class);
assertEquals("Foo", foo);
String bar = ctx.getBean("bar", String.class);
assertEquals("Bar", bar);
Pet pet = ctx.getBean(Pet.class);
assertNotNull("pet", pet);
assertEquals("Dogbert", pet.getName());
Employee employee = ctx.getBean(Employee.class);
assertNotNull("employee", employee);
assertEquals("Dilbert", employee.getName());
assertEquals("???", employee.getCompany());
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.tests.sample.beans.Employee;
import org.springframework.tests.sample.beans.Pet;
import static org.junit.Assert.*;
/**
* Integration tests for loading an {@code ApplicationContext} from a
* Groovy script with the TestContext framework.
*
* @author Sam Brannen
* @since 4.1
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("context.groovy")
public class GroovySpringContextTests implements BeanNameAware, InitializingBean {
private boolean beanInitialized = false;
private String beanName = "replace me with [" + getClass().getName() + "]";
@Autowired
private ApplicationContext applicationContext;
private Employee employee;
@Autowired
private Pet pet;
@Autowired(required = false)
protected Long nonrequiredLong;
@Resource
protected String foo;
protected String bar;
@Autowired
protected final void setEmployee(final Employee employee) {
this.employee = employee;
}
@Resource
protected final void setBar(final String bar) {
this.bar = bar;
}
@Override
public final void setBeanName(final String beanName) {
this.beanName = beanName;
}
@Override
public final void afterPropertiesSet() throws Exception {
this.beanInitialized = true;
}
@Test
public final void verifyBeanInitialized() {
assertTrue("This test bean should have been initialized due to InitializingBean semantics.",
this.beanInitialized);
}
@Test
public final void verifyBeanNameSet() {
assertEquals("The bean name of this test instance should have been set to the fully qualified class name "
+ "due to BeanNameAware semantics.", getClass().getName(), this.beanName);
}
@Test
public final void verifyAnnotationAutowiredFields() {
assertNull("The nonrequiredLong property should NOT have been autowired.", this.nonrequiredLong);
assertNotNull("The application context should have been autowired.", this.applicationContext);
assertNotNull("The pet field should have been autowired.", this.pet);
assertEquals("Dogbert", this.pet.getName());
}
@Test
public final void verifyAnnotationAutowiredMethods() {
assertNotNull("The employee setter method should have been autowired.", this.employee);
assertEquals("Dilbert", this.employee.getName());
}
@Test
public final void verifyResourceAnnotationWiredFields() {
assertEquals("The foo field should have been wired via @Resource.", "Foo", this.foo);
}
@Test
public final void verifyResourceAnnotationWiredMethods() {
assertEquals("The bar method should have been wired via @Resource.", "Bar", this.bar);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.tests.sample.beans.Employee;
import org.springframework.tests.sample.beans.Pet;
import static org.junit.Assert.*;
/**
* Integration test class that verifies proper support for mixing XML
* configuration files and Groovy scripts to load an {@code ApplicationContext}
* using the TestContext framework.
*
* @author Sam Brannen
* @since 4.1
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "contextA.groovy", "contextB.xml" })
public class MixedXmlAndGroovySpringContextTests {
@Autowired
private Employee employee;
@Autowired
private Pet pet;
@Autowired
protected String foo;
@Autowired
protected String bar;
@Test
public final void verifyAnnotationAutowiredFields() {
assertNotNull("The employee field should have been autowired.", this.employee);
assertEquals("Dilbert", this.employee.getName());
assertNotNull("The pet field should have been autowired.", this.pet);
assertEquals("Dogbert", this.pet.getName());
assertEquals("The foo field should have been autowired.", "Groovy Foo", this.foo);
assertEquals("The bar field should have been autowired.", "XML Bar", this.bar);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy;
import org.springframework.test.context.ContextConfiguration;
/**
* Extension of {@link GroovySpringContextTests} that declares a Groovy
* script using a relative path.
*
* @author Sam Brannen
* @since 4.1
* @see GroovySpringContextTests
* @see AbsolutePathGroovySpringContextTests
*/
@ContextConfiguration(locations = "../groovy/context.groovy", inheritLocations = false)
public class RelativePathGroovySpringContextTests extends GroovySpringContextTests {
/* all tests are in the superclass */
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy
import org.springframework.tests.sample.beans.Employee;
import org.springframework.tests.sample.beans.Pet;
/**
* Groovy script for defining Spring beans for integration tests.
*
* @author Sam Brannen
* @since 4.1
*/
beans {
foo String, 'Foo'
bar String, 'Bar'
employee(Employee) {
name = "Dilbert"
age = 42
company = "???"
}
pet(Pet, 'Dogbert')
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.groovy
/**
* Groovy script for defining Spring beans for integration tests.
*
* @author Sam Brannen
* @since 4.1
*/
beans {
foo String, 'Groovy Foo'
bar String, 'Groovy Bar'
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="employee" class="org.springframework.tests.sample.beans.Employee">
<property name="name" value="Dilbert" />
<property name="age" value="42" />
<property name="company" value="???" />
</bean>
<bean id="pet" class="org.springframework.tests.sample.beans.Pet">
<constructor-arg value="Dogbert" />
</bean>
<bean id="bar" class="java.lang.String">
<constructor-arg value="XML Bar" />
</bean>
</beans>

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.web;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Sam Brannen
* @since 4.1
* @see BasicXmlWacTests
*/
// Config loaded from BasicGroovyWacTestsContext.groovy
@ContextConfiguration
public class BasicGroovyWacTests extends AbstractBasicWacTests {
@Test
public void groovyFooAutowired() {
assertEquals("Groovy Foo", foo);
}
}

View File

@@ -0,0 +1,3 @@
package org.springframework.test.context.web
beans { foo String, 'Groovy Foo' }