【问题标题】:Can I mock CrudRepository with Spring Data JDBC without any database using Spring Boot?我可以在没有使用 Spring Boot 的任何数据库的情况下使用 Spring Data JDBC 模拟 CrudRepository 吗?
【发布时间】:2020-06-03 13:42:56
【问题描述】:

我正在开发一个使用 Spring Boot 2 和 Spring Data JDBC 的应用程序。最终的应用程序将使用 MySQL。

我目前有一个持久层和一个服务层以及一些从 CrudRepository 派生的存储库。

对于我的单元测试,我真的想在没有任何数据库的情况下进行单元测试。甚至没有 HSQL。我知道这里有几种不同的哲学可以订阅,但我想切换到纯单元测试,看看它是如何发挥作用的。我将在集成测试中使用数据库。

我的测试文件夹中有一个单独的application.properties,我在其中有一个单独的测试配置。

如果application.properties 中没有定义数据源,Spring Boot 将默认使用 HSQL。但同样,我想在没有任何数据库的情况下运行我的测试,并且只模拟我的 CrudRepository 实现。我尝试通过在application.properties 中使用以下不同变体来禁用 Spring Boot 的数据库自动配置:

spring.autoconfigure.exclude= \
  org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
  org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
  org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
  org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration

在我的测试中,我尝试做这样的事情:

@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest
public class UserServiceTest {

    private UserService userService;

    @MockBean
    private UserRepository userRepository;

    @BeforeEach
    void setUp() {
        userService = new UserService(userRepository);
    }

    @Test
    public void doSomeTest() {

         // Test code goes here

    }

}

我在服务中使用基于构造函数的依赖注入。但是,我从 Spring 收到如下错误:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'package.userRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

我想要的是一个模拟的 userRepository,我可以在其中预先配置一个伪造的存储库以返回虚拟数据。但似乎删除数据库配置会完全删除 CrudRepository,因此 spring boot 应用程序的任何部分都无法启动。还是我错过了其他东西。

我正在使用 Eclipse、Maven、Mockito 和 JUnit5。我应该注意,如果我对测试 mysql 数据库运行“单元测试”,一切都会正常工作,所以我知道代码或测试或一般设置没有任何问题。只有当我想摆脱数据库时才会出现问题。

我是一名初级 Java 开发人员,这样做是为了好玩,所以我可能会遗漏一些明显的东西。在网上搜索 Spring Data JDBC 很困难,因为我几乎只能找到与 JPA 相关的解决方案。

【问题讨论】:

  • 你不能有一个可以在@BeforEach 中定义的测试的虚拟数据列表吗?
  • 我认为 spring boot 不会配置 HSQL 数据库,除非您通过明确定义它。依赖和application.properties?检查您的应用程序是否将 HSQL 作为其依赖项。同样,即使您使用的是 HSQL,您仍然需要引导自动配置来设置您使用 HSQL,而您显然已将其排除在外。
  • 你说得对,启用了 HSQL 是因为我在 maven pom.xml 中启用了它。但除非我配置数据源,否则 Spring Boot 会失败,并显示“无法配置数据源:未指定 'url' 属性并且无法配置嵌入式数据源。”。似乎没有办法完全禁用数据库,但仍保持我的 CrudRepository 完整以供测试。

标签: spring spring-boot mockito spring-data-jdbc


【解决方案1】:

@SpringBootTest 加载所有上下文。 Spring boot – @SpringBootTest

在底层,@SpringBootTest 试图模仿 Spring Boot 框架添加的用于创建上下文的过程,例如它根据包结构决定扫描什么,从预定义的位置加载外部配置,可选地运行自动配置启动器等等。

正如我们看到的,这个注解启动并配置了几乎整个 测试开始之前的应用程序,我们应该使用@SpringBootTest 编写使用应用程序进程的集成测试和 依赖关系。

包括UserService。我猜它找不到UserRepository 所以它失败了。

我猜你应该删除这些字符串

spring.autoconfigure.exclude= \
  org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
  org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
  org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
  org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration

并像这样测试

@ExtendWith(SpringExtension.class)
@SpringBootTest
@Transactional
public class UserServiceTest {

    @TestConfiguration
    class UserServiceTestContextConfiguration {

        @Bean
        public UserService userService() {
            return new UserService(userRepository);
        }
    }

    @Autowired
    private UserService userService;

    @MockBean
    private UserRepository userRepository;

    // write test cases here
}

我拿了it from here

请记住,Spring 专门处理 @TestConfiguration,所以不要用它“打你的腿”Spring boot – @TestConfiguration

在 Spring Boot 中,任何配置在使用 @TestConfiguration 注释的顶级类中的 bean 都不会通过组件扫描被拾取。我们必须向包含测试用例的类显式注册@TestConfiguration 类。

【讨论】:

  • 感谢您的建议,我会阅读更多关于@TestConfiguration 的信息。但是,您的示例无法编译:“无法对非静态字段 userRepository 进行静态引用”,因此我无法直接尝试。
  • @JonathanJogenfors 是的,我错过了。实际上,您可以从代码中删除 @SpringBootTest 并且根本不使用 @TestConfiguration。我想到了静态,但还不知道如何正确解决它(你可以将userRepository设为静态,但我认为它会破坏你的测试行为)
  • 不用担心。我让它在我对您的评论的编辑中起作用。现在开始嘲笑!我唯一的问题是没有主开关说“不要触摸任何数据库”,例如我必须将主文件夹中的主 schema.sql 重命名为 schema-mysql.sql 以便 hsql 数据库不会尝试加载一个 mysl 模式(并失败)。不过,我可以忍受这个。
  • @JonathanJogenfors 很高兴我帮助了你!您可以使用“Spring 配置文件”提供不同的测试环境。 baeldung.com/spring-profiles 。对于不同的配置文件,使用名称中带有配置文件的不同属性。你也可以用@Conditional激活不同的@bean
  • 您也可以为类似的测试创建抽象类,并针对不同的情况实现它,提供所需的注释或配置
猜你喜欢
  • 2017-10-09
  • 1970-01-01
  • 2018-07-12
  • 2020-12-23
  • 2021-01-22
  • 2020-10-21
  • 2020-04-24
  • 2021-05-18
  • 2014-04-17
相关资源
最近更新 更多