java - 使用 Spring Data 和 MongoDB 的单元/集成测试无法模拟存储库

标签 java spring mongodb unit-testing spring-mvc

事先的一些小信息:

  • 不是端到端测试,它指的是现在多个模块的集成测试。
  • 由于之前的一些困难,我们不得不更改很多测试代码,我正在努力降低集成级别,以便我们回到单元测试。但是,在我被允许减少配置等之前,我必须先让一切恢复正常。
  • 如果你读了最后一段,你已经知道了,但无论如何:我知道这不是一个好方法,我正在努力改变它,但我必须先这样做。

依赖

Spring 启动 1.3.0
Spring Mongo 1.3.3
Spring 安全 3.1.4
Spring Security Cas 4.0.2
Flapdoodle Embedmongo 1.46.0

基地

现在,我们有一个带有注释的抽象测试类

@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(TestConfig.class)@WebAppConfiguration

TestConfig 类如下所示:

@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;
        }
    }

我现在正在创建几个请求,这些请求将传递给父类(super class)以进行安全测试,并且(因为无论如何所有测试都只有一个成功案例)然后我尝试通过 verify(mock) 验证对 Daos 和 Repositories 的相应调用。

Bean 由 @Resource 注入(inject) Controller ,就像我在测试类中使用它们一样。

问题

出于某种原因,Daos 正在按预期工作(被创建,行为被指定,被调用并且可以被验证),存储库不是 - 常规代理被创建和使用。在使用 @Order(Ordered.HIGHEST_PRECEDENCE) 之前,由于已经注册的顶级 bean 拒绝被覆盖,因此简单地跳过了 bean 创建(并这样记录)。

采用此方法后,Repository-beans 已被覆盖而不是被跳过(当然,也被记录为这样)。 bean 级别的 @Primary 应该确保使用模拟而不是组件扫描创建的实际 bean - 以及其他测试实例,这些实例不会启动整个应用程序和嵌入式Mongo,这按预期工作 - 但在这里,它没有。

我尝试过的事情

  • 设置@Order
  • 排除@EnableMongoRepositories-配置
  • 手动注入(inject)创建的 Mocks
  • 全面的网络研究
  • 设置 bean 角色
  • 重新触发 bean 的创建
  • 创建 dao-bean 时触发 bean 创建

我已经找了好几天了,总是,而且我偶然发现的唯一可能的解决方案是:创建一个 xml 配置(这是不行的,因为我们应该创建所有东西而不需要 xml-文件),使用 Fongo(这将需要为这一步导入一个新的依赖项,因为数据库测试完全发生在其他地方,然后将其删除),或者禁用 bean 覆盖(我完全不知道该怎么做并且 Spring 文档并不是很有帮助 - 是的,该方法就在那里,但每当我尝试这样做时,它都不会影响当前上下文)。

最佳答案

抱歉,这更适合评论而不是答案,但格式太糟糕了......

不知道为什么它不起作用,但是您是否尝试使用 @Configuration bean 的显式导入与 ComponenScan 的使用?

例如:

@SpringApplicationConfiguration(classes = TestClass.TestConfiguration.class)
public class TestClass extends AbstractTest {

    @Configuration
    @Import( TestConfig.class )
    public static class TestConfiguration {
       //...
    }
}

@Configuration
@EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
// @ComponentScan(value = { "package1", "package2" }) // GET RID OF THIS
@Import( { TestMongoConfiguration.class /*, OtherConfig.class, ... */ } )
public class TestConfig {

}

这样您就可以控制配置加载的顺序。

关于java - 使用 Spring Data 和 MongoDB 的单元/集成测试无法模拟存储库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34611571/

相关文章:

java - authc 过滤器未使用 spring 在 shiro 中调用 MyRealm

spring - 使用 Spring Webflux 恢复文件下载以及 Spring 中的静态文件服务

spring - 使用 Spring Java Config 时资源不可用 Tomcat 404 错误

ruby-on-rails - Mongoid:在 has_many 关系中搜索

MongoDB按二级查找表排序

java - 从 cmd 运行 .class 文件

java - 安装 Genymotion Eclipse 插件

java - 评估方法需要很长时间 - 使用 Jpmml 的 PMML 模型

java - JpaRepository 缓存新创建的对象。如何刷新它?

javascript - Mongoose:如何使用回调中的变量更新文档?