一些小信息事先说明:
- 这与端对端测试无关,它指的是目前涉及多个模块的集成测试。
- 由于之前遇到了几个困难,我们不得不改变很多测试代码,我正在努力降低集成级别,使我们回归单元测试。然而,在减少配置和其他内容之前,我必须先让所有内容重新起作用。
- 如果您已经阅读了最后一段,您已经知道,但无论如何:我知道这不是一个好方法,我正在努力改变它,但我必须首先这样做。
依赖关系
Spring Boot 1.3.0
Spring Mongo 1.3.3
Spring Security 3.1.4
Spring Security Cas 4.0.2
Flapdoodle Embedmongo 1.46.0
基础
现在,我们有一个带有注释的抽象测试类
@RunWith(SpringJUnit4ClassRunner.class)
, @SpringApplicationConfiguration(TestConfig.class)
和@WebAppConfiguration
。
TestConfig-class看起来像这样:
@Configuration
@EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
@ComponentScan(value = { "package1", "package2" })
public class TestConfig {
}
正如你所看到的,它扫描了这两个包中的所有内容,并提取了几个其他的配置类:
@Configuration
// needed if working with Spring-Data-Repository interfaces and subprojects
// http://stackoverflow.com/questions/29084824/spring-repository-components-not-found-in-gradle-subproject-springboot
@EnableMongoRepositories({ "package2.subpackage" })
public class ModelConfiguration {
}
并且
@Configuration
@EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
@EnableMongoRepositories(basePackages = { "package2" })
public class TestMongoConfiguration {
private static final String DESTROY_METHOD_CLOSE = "close";
private static final String DESTROY_METHOD_STOP = "stop";
private static final MongodStarter STARTER = MongodStarter.getDefaultInstance();
@Autowired
private MongoProperties mongoProperties;
@Autowired(required = false)
private MongoClientOptions mongoClientOptions;
@Autowired
private Environment environment;
@Bean(destroyMethod = DESTROY_METHOD_CLOSE)
public MongoClient mongo() throws IOException {
Net net = mongodProcess().getConfig().net();
mongoProperties.setHost(net.getServerAddress().getHostName());
mongoProperties.setPort(net.getPort());
return mongoProperties.createMongoClient(this.mongoClientOptions, environment);
}
@Bean(destroyMethod = DESTROY_METHOD_STOP)
public MongodProcess mongodProcess() throws IOException {
return mongodExecutable().start();
}
@Bean(destroyMethod = DESTROY_METHOD_STOP)
public MongodExecutable mongodExecutable() throws IOException {
return STARTER.prepare(mongodConfig());
}
@Bean
public IMongodConfig mongodConfig() throws IOException {
return new MongodConfigBuilder().version(Version.Main.PRODUCTION).build();
}
}
这是我的测试类的一部分:
@SpringApplicationConfiguration(classes = TestClass.TestConfiguration.class)
public class TestClass extends AbstractTest {
@Order(Ordered.HIGHEST_PRECEDENCE)
public static class TestConfiguration {
@Bean
@Primary
public FooRepository fooRepository() {
FooRepository mock = mock(FooRepository.class);
// mockbehaviour
return mock;
}
@Bean
@Primary
public FooDao fooDao() {
FooDao mock = mock(FooDao.class);
//Mock behaviour
return mock;
}
@Bean
@Primary
public BarDao barDao() {
BarDao mock = mock(BarDao.class);
//MockBehaviour
return mock;
}
@Bean
@Primary
public BarRepository barRepository() {
BarRepository mock = mock(BarRepository.class);
return mock;
}
}
我现在正在创建多个请求,这些请求将被传递给超类进行安全测试,然后(由于所有测试都只有一个成功的情况),我尝试通过verify(mock)来验证对应的Daos和Repositories的调用。
这些Bean是通过@Resource注入到控制器中的,我在测试类中也是这样使用它们的。
问题:
由于某种原因,Daos按预期工作(被创建、行为被指定、被调用并可以验证),而Repositories则没有——常规代理被创建并使用。在使用@Order(Ordered.HIGHEST_PRECEDENCE)之前,bean的创建被简单地跳过了(并记录为这样),因为顶层bean已经注册并拒绝被覆盖。
在重新排序后,Repository-beans已经被覆盖而不是被跳过(当然,也被记录下来)。bean级别的@Primary应该确保使用模拟对象而不是组件扫描创建的实际bean,在其他不启动整个应用程序和嵌入式Mongo的测试实例上,这是按预期工作的,但在这里,它却没有起作用。
我尝试过的事情:
- 设置@Order - 排除@EnableMongoRepositories配置 - 手动注入创建的Mocks - 彻底的网络研究 - 设置bean角色 - 重新触发bean的创建 - 在创建dao-bean时触发bean的创建
我已经寻找了几天,唯一可能的解决方案是:创建一个xml配置(这是不可行的,因为我们应该创建一切而不需要xml文件),使用Fongo(这将需要导入一个新的依赖项来完成这一步,因为数据库测试完全发生在其他地方,然后删除它),或禁用bean覆盖(我完全不知道如何做,Spring文档也没有帮助——是的,方法在那里,但每当我尝试这样做时,它都不影响当前上下文)。