我正在寻找使用 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”})”重复很多。
有什么建议吗?
问候,
弗洛里安
I'm looking for best practices for setting up unit and integration tests using Spring.
I usually use 3 kind of tests:
- "real" unit tests (no dependencies)
- tests run either as "unit" test (in-memory db, local calls, mock
objects,...) or as integration test
(persistent db, remote calls,...)
- tests run only as integration tests
Currently I only have tests of the second category, which is the tricky part.
I set-up a base test class like:
@ContextConfiguration(locations = { "/my_spring_test.xml" })
public abstract class AbstractMyTestCase extends AbstractJUnit4SpringContextTests
And "unit" tests like:
public class FooTest extends AbstractMyTestCase
with autowired attributes.
What's the best way to run the test in a different (integration test) environment? Subclass the test and override the ContextConfiguration?
@ContextConfiguration(locations = { "/my_spring_integration_test.xml" })
public class FooIntegrationTest extends FooTest
Would this work (I cannot currently easily test it here)? The problem with this approach is that "@ContextConfiguration(locations = { "/my_spring_integration_test.xml" })" is duplicated a lot.
Any suggestions?
Regards,
Florian
发布评论
评论(4)
我扩展了 GenericXmlContextLoader
public class MyContextLoader extends GenericXmlContextLoader {
并重写
protected String[]generateDefaultLocations(Class> clazz)
方法来收集 a 的配置文件名我可以通过 SystemProperty (-Dtest.config=) 指定的目录。
我还修改了以下方法以不修改任何位置
我使用此上下文加载器,如下
所示使用指示配置文件源的 SystemProperty 运行测试使您现在可以使用完全不同的配置。
当然,使用 SystemProperty 只是指定配置位置的一种策略。您可以在
generateDefaultLocations()
中做任何您想做的事情。编辑:
此解决方案使您能够使用完全不同的应用程序上下文配置(例如,对于模拟对象),而不仅仅是不同的属性。您不需要构建步骤即可将所有内容部署到“类路径”位置。如果没有给出系统属性,我的具体实现还使用用户名作为默认值来查找配置目录(src/test/resources/{user})(可以轻松地为项目中的所有开发人员维护特定的测试环境)。
PropertyPlaceholder 的使用仍然是可能的并且推荐。
编辑:
Spring版本3.1.0 将支持XML 配置文件/环境抽象 这与我的解决方案类似,可以为不同的环境/配置文件选择配置文件。
I extended the GenericXmlContextLoader
public class MyContextLoader extends GenericXmlContextLoader {
and overrote the
protected String[] generateDefaultLocations(Class<?> clazz)
method to collect the config file names of a directory which I can specify by a SystemProperty (-Dtest.config=).
I also modified the follwowing method to NOT modify any locations
I use this context loader like this
Running the test with a SystemProperty indicating the source of the config files enables you now to use completely different configurations.
The usage of a SystemProperty is of course only one strategy to specify the configuration location. You can do whatever you want in
generateDefaultLocations()
.EDIT:
This solution enables you to use complete different application context configurations (e.g. for mock objects) and not only different properties. You do not need a build step to deploy everything to your "classpath" location. My concrete implementation also used the users name as default to look for a configuration directory (src/test/resources/{user}) if no system property is given (makes it easy to maintain specific test environments for all developers on the project).
The usage of the PropertyPlaceholder ist still possible and recommended.
EDIT:
Spring Version 3.1.0 will support XML profiles/Environment Abstraction which is similar to my solution and will enable the choice of configuration files for different environments/profiles.
我会选择这个版本:
在
my_spring_test.xml
中,我会使用PropertyPlaceHolderConfigurer
机制。JPA 示例:
现在您需要做的就是在类路径上拥有不同版本的 test.properties,以进行内存中测试和实际集成测试(当然,需要存在相应的驱动程序类)。您甚至可以设置系统属性来覆盖属性值。
如果你想用maven来准备这个,你会发现用maven复制文件并不简单。您将需要一种执行代码的方法,标准选择是 maven-antrun-plugin< /a> 和 gmaven-maven-plugin。
无论哪种方式:有两个配置文件,例如在 src/main/config 中,并添加两个插件执行,一个在
generate-test-resources
阶段,一个在pre-integration-test
阶段代码>.这是 GMaven 版本:I'd go with this version:
and in
my_spring_test.xml
, I'd use thePropertyPlaceHolderConfigurer
mechanism.Example for JPA:
Now all you need to do is have different versions of test.properties on the class path for in-memory and real integration tests (and of course the respective driver classes need to be present). You can even set system properties to overwrite the property values.
If you want to prepare this with maven, you will find that copying files with maven is not trivial. You will need a way to execute code, the standard choices being the maven-antrun-plugin and gmaven-maven-plugin.
Either way: have two configuration files, e.g. in src/main/config and add two plugin executions, one in phase
generate-test-resources
and one in phasepre-integration-test
. Here's the GMaven version:我没有成功使用 Spring 3.x context:property-placeholder 标签。我使用了旧式 bean 标签和属性文件,并且能够在我的代码和数据库之间建立连接,如下所示:
这是属性文件的示例:
设置 JUnit 测试:
然后我像这样 对我来说,但每个人做事的方式都略有不同。希望这有帮助。
I have had no success in using Spring 3.x context:property-placeholder tag. I have used the old fashion bean tag along with a properties file and was able to set up a connection between my code and my database like so:
Here's an example of the properties file:
Then I set up my JUnit test like so:
That worked for me, but everybody does things a little differently. Hope this helps.
我最近遇到了同样的问题并查看 @ContextConfiguration 注释的文档,我注意到 inheritLocations 选项。
通过将其添加到我的类中,例如
我发现我能够根据需要覆盖 ContextConfiguration。
I recently ran in to the same problem and looking at the documentation for the @ContextConfiguration annotation, I noticed the inheritLocations option.
By adding this to my class e.g.
I found that I was able to override the ContextConfiguration as desired.