Spring:单元和集成测试
我正在寻找使用Spring设置单元和集成测试的最佳实践。
我通常使用3种测试:
- “真正的”unit testing(没有依赖)
- 测试作为“单元”测试(内存数据库,本地调用,模拟对象,……)或集成测试(持久数据库,远程调用,……)运行
- 测试仅作为集成测试运行
目前我只有第二类测试,这是棘手的部分。 我设置了一个基础测试类,如:
@ContextConfiguration(locations = { "/my_spring_test.xml" }) public abstract class AbstractMyTestCase extends AbstractJUnit4SpringContextTests
而“单位”测试如下:
public class FooTest extends AbstractMyTestCase
使用自动assembly的属性。
在不同(集成测试)环境中运行测试的最佳方法是什么? 对测试进行子类化并覆盖ContextConfiguration?
@ContextConfiguration(locations = { "/my_spring_integration_test.xml" }) public class FooIntegrationTest extends FooTest
这是否有效(我目前无法在此轻松测试)? 这种方法的问题是“@ContextConfiguration(locations = {”/ my_spring_integration_test.xml“})”重复了很多。
有什么建议么?
此致,弗洛里安
我扩展了GenericXmlContextLoader
public class MyContextLoader extends GenericXmlContextLoader {
并覆盖了
protected String[] generateDefaultLocations(Class> clazz)
收集我可以通过SystemProperty(-Dtest.config =)指定的目录的配置文件名的方法。
我还修改了follwowing方法以不修改任何位置
@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配置文件/环境抽象 ,类似于我的解决方案,可以为不同的环境/配置文件选择配置文件。
我会选择这个版本:
ContextConfiguration(locations = { "/my_spring_test.xml" }) public abstract class AbstractMyTestCase extends AbstractJUnit4SpringContextTests
在my_spring_test.xml
,我使用了PropertyPlaceHolderConfigurer
机制。
JPA示例:
现在,您需要做的就是在类路径上有不同版本的test.properties,用于内存和实际集成测试(当然还需要存在相应的驱动程序类)。 您甚至可以设置系统属性来覆盖属性值。
如果你想用maven准备这个,你会发现用maven复制文件并不简单。 您将需要一种执行代码的方法,标准选择是maven-antrun-plugin和gmaven-maven-plugin 。
无论哪种方式:有两个配置文件,例如在src / main / config中添加两个插件执行,一个是阶段generate-test-resources
,另一个是阶段pre-integration-test
。 这是GMaven版本:
org.codehaus.gmaven gmaven-plugin 1.3 pre-integration-test execute new File( pom.build.testOutputDirectory, "test.properties" ).text = new File( pom.basedir, "src/main/config/int-test.properties" ).text; generate-test-resources execute new File( pom.build.testOutputDirectory, "test.properties" ).text = new File( pom.basedir, "src/main/config/memory-test.properties" ).text;
我没有成功使用Spring 3.x上下文:property-placeholder标记。 我使用旧的时尚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); } }
这对我有用,但每个人做的事情都有所不同。 希望这可以帮助。
我最近遇到了同样的问题并查看了@ContextConfiguration注释的文档 ,我注意到了inheritLocations选项。
通过将此添加到我的class级,例如
@ContextConfiguration(locations = { "/my_spring_integration_test.xml" }, inheritLocations=false) public class FooIntegrationTest extends FooTest
我发现我能够根据需要覆盖ContextConfiguration。