我正在寻找使用Spring设置单元和集成测试的最佳实践。
我通常使用3种测试:
目前我只有第二类测试,这是一个棘手的部分。 我设置了一个基础测试类,如:
@ContextConfiguration(locations = { "/my_spring_test.xml" })
public abstract class AbstractMyTestCase extends AbstractJUnit4SpringContextTests
“单位”测试如下:
public class FooTest extends AbstractMyTestCase
使用自动装配的属性。
在不同的(集成测试)环境中运行测试的最佳方法是什么?对测试进行子类化并覆盖ContextConfiguration?
@ContextConfiguration(locations = { "/my_spring_integration_test.xml" })
public class FooIntegrationTest extends FooTest
这是否有效(我目前无法在此轻松测试)?这种方法的问题是“@ContextConfiguration(locations = {”/ my_spring_integration_test.xml“})”重复了很多。
有什么建议吗?
此致 弗洛里安
答案 0 :(得分:4)
public class MyContextLoader extends GenericXmlContextLoader {
并覆盖了
protected String[] generateDefaultLocations(Class<?> clazz)
收集我可以通过SystemProperty指定的目录的配置文件名的方法(-Dtest.config =)。
我还修改了folllwowing方法以不修改任何位置
@Override
protected String[] modifyLocations(Class<?> clazz, String... locations) {
return locations;
}
我像这样使用这个上下文加载器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = MyContextLoader.class)
public class Test { .... }
使用指示配置文件源的SystemProperty运行测试,现在可以使用完全不同的配置。
SystemProperty的使用当然只是指定配置位置的一种策略。你可以在generateDefaultLocations()
中做任何你想做的事。
修改强>
此解决方案使您可以使用完整的不同应用程序上下文配置(例如,对于模拟对象),而不仅仅是不同的属性。您无需构建步骤即可将所有内容部署到“类路径”位置。如果没有给出系统属性,我的具体实现还使用用户名作为默认值来查找配置目录(src / test / resources / {user})(使得为项目中的所有开发人员维护特定的测试环境变得容易)。
仍然可以使用PropertyPlaceholder。
修改强>:
Spring版本3.1.0将支持与我的解决方案类似的 XML profiles/Environment Abstraction ,并且可以为不同的环境/配置文件选择配置文件。
答案 1 :(得分:2)
我会选择这个版本:
ContextConfiguration(locations = { "/my_spring_test.xml" })
public abstract class AbstractMyTestCase extends AbstractJUnit4SpringContextTests
在my_spring_test.xml
中,我会使用PropertyPlaceHolderConfigurer
机制。
JPA示例:
<context:property-placeholder
system-properties-mode="OVERRIDE"
location="classpath:test.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${test.database.driver}" />
<property name="url" value="${test.database.server}" />
<property name="username" value="${test.database.user}" />
<property name="password" value="${test.database.password}" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="test" />
<property name="dataSource" ref="dataSource" />
<property name="persistenceXmlLocation"
value="classpath:META-INF/persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="${test.database.update}" />
<property name="database" value="${test.database.databasetype}" />
</bean>
</property>
</bean>
现在您需要做的就是在类路径上使用不同版本的test.properties进行内存和实际集成测试(当然还需要存在相应的驱动程序类)。您甚至可以设置系统属性来覆盖属性值。
如果您想使用maven进行准备,您会发现使用maven复制文件并非易事。您需要一种执行代码的方法,标准选择是maven-antrun-plugin和gmaven-maven-plugin。
无论哪种方式:有两个配置文件,例如在src / main / config中添加两个插件执行,一个在阶段generate-test-resources
,一个在阶段pre-integration-test
。这是GMaven版本:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<phase>pre-integration-test</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
new File(
pom.build.testOutputDirectory,
"test.properties"
).text = new File(
pom.basedir,
"src/main/config/int-test.properties"
).text;
</source>
</configuration>
</execution>
<execution>
<phase>generate-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
new File(
pom.build.testOutputDirectory,
"test.properties"
).text = new File(
pom.basedir,
"src/main/config/memory-test.properties"
).text;
</source>
</configuration>
</execution>
</executions>
</plugin>
答案 2 :(得分:0)
我没有成功使用Spring 3.x上下文:property-placeholder标记。我使用旧的时尚bean标签和属性文件,并能够在我的代码和我的数据库之间建立连接,如下所示:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/com/my/package/database.properties"/>
</bean>
<bean id="myDatasource" class="oracle.ucp.jdbc.PoolDataSourceFactory"
factory-method="getPoolDataSource">
<property name="URL" value="${JDBC_URL}"/>
<property name="user" value="${JDBC_USERNAME}"/>
<property name="password" value="${JDBC_PASSWORD}"/>
<property name="connectionFactoryClassName"
value="oracle.jdbc.pool.OracleConnectionPoolDataSource"/>
<property name="ConnectionPoolName" value="SCDB_POOL"/>
<property name="MinPoolSize" value="5"/>
<property name="MaxPoolSize" value="50"/>
<property name="connectionWaitTimeout" value="30"/>
<property name="maxStatements" value="100"/>
</bean>
以下是属性文件的示例:
JDBC_URL=jdbc:oracle:thin:@myDB:1521:mySchema
JDBC_USERNAME=username
JDBC_PASSWORD=password
然后我像这样设置我的JUnit测试:
@ContextConfiguration(locations = {"/com/my/pkg/test-system-context.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class HeaderDaoTest {
@Autowired
HeaderDao headerDao;
@Test
public void validateHeaderId() {
int headerId = 0;
headerId = headerDao.getHeaderId();
assertNotSame(0,headerId);
}
}
这对我有用,但每个人都做的事情有点不同。希望这会有所帮助。
答案 3 :(得分:0)
我最近遇到了同样的问题并查看documentation for the @ContextConfiguration annotation,我注意到 inheritLocations 选项。
将此添加到我的班级,例如
@ContextConfiguration(locations = { "/my_spring_integration_test.xml" }, inheritLocations=false)
public class FooIntegrationTest extends FooTest
我发现我能够根据需要覆盖ContextConfiguration。