Spring Boot:单元测试存储库方法的最佳策略是什么?

时间:2018-07-19 08:48:52

标签: spring-boot testing hql spring-repositories

我们有很多类似如下的连接和提取方法:

@Query(
        "select new com.vulog.user.entity.DTO.UserBillingDTO(" +
                    "u.id as id, " +
                    "u.firstName as firstName, " +
                    "u.lastName as lastName, " +
                    "e.tokenId as billingTokenID," +
                    "u.fleetId as fleetId," +
                    "e.id as entityId, " +
                    "u.userName as userName, " +
                    "u.locale as locale) " +
                "from User as u "  +
                "join u.profiles as p "  +
                "join p.entity as e "  +
                "where u.id = :userId")
UserBillingDTO findUserForBilling(@Param("userId") String userId);

我想在测试中介绍此类方法,并查看我们的HQL查询是否返回了预期的结果。

问题是我如何才能轻松地填充本地数据库以测试我们方法的结果?

  • 一种明显的方法是使用以下方法在测试设置中创建实体 码。但我担心此测试的可读性很低。
  • 我想到的另一个想法是从我们的数据库中转储数据库 测试平台,使用它来设置测试,然后仅运行查询以 检查结果。

您还能想到其他吗?我该如何编写一个易于维护的,易于团队使用的测试套件?

编辑:

2 个答案:

答案 0 :(得分:1)

如果您不使用数据库特定的功能,例如自定义特定于Oracle的SQL函数,您可以在@SpringBootTest测试中设置嵌入式数据库。使用@AutoConfigureTestDatabase注释对测试类进行注释,例如将默认应用程序DataSource bean替换为嵌入式内存数据库:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)

您可以根据81.5 Use a Higher-level Database Migration Tool章使用Flyway或Liquibase来填充数据库。根据文档:

  

您还可以使用Flyway为特定情况提供数据。例如,您可以将特定于测试的迁移放置在src / test / resources中,并且仅在您的应用程序开始进行测试时才运行它们。另外,您可以使用特定于配置文件的配置来自定义spring.flyway.locations,以便仅在特定配置文件处于活动状态时才运行某些迁移。例如,在application-dev.properties中,您可以指定以下设置:

答案 1 :(得分:1)

使用存储库填充

一种可能性是在测试中创建记录。这就是您所描述的显而易见的解决方案。对于当前代码,您可以执行以下操作:

@Test
public void findUserForBilling() {
    repository.saveAll(Lists.newArrayList(
        new User("1", "John", "Doe", "JDoe123", new Profile(..., new ProfileEntity(1, "token123"))),
        new User("2", "Jane", "Doe", "TheJane", new Profile(..., new ProfileEntity(2, "token234")))));
    UserBillingDTO dto = repository.findUserForBilling("1");
    assertThat(dto.getId()).isEqualTo("1");
    // ...
}

尽管在某些情况下,您的测试数据可能会占据一定的位置,但在这种情况下,它仅占几行,仅比通常的单元测试准备/给定方案多。

  

请注意:在这种类型的测试中,您并未测试实体映射。如果您的实体映射中存在问题,您将无法判断使用这些测试。

使用SQL文件填充

另一种可能性是使用单独的SQL文件,例如user-dataset.sql中的src/test/resources

insert into user (id, firstname, lastname) values ("1", "John", "Doe");
insert into user (id, firstname, lastname) values ("2", "Jane", "Doe");
--- ...

然后您可以使用@Sql批注将该数据集包含在测试中,例如:

@RunWith(SpringRunner.class)
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Sql("classpath:user-dataset.sql") // Add this
public class UserRepositoryTest {
    // ...
}

您可以将@Sql批注添加到测试类,甚至添加到单个测试方法,例如:

@Test
@Sql("classpath:user-dataset.sql") // Add this
public void findUserForBilling() {
    UserBillingDTO dto = repository.findUserForBilling("1");
    assertThat(dto.getId()).isEqualTo("1");
    // ...
}
  

注意:如果我没记错的话,Spring将为测试类创建一次数据源。如果您为每种测试方法执行数据集,则必须添加delete语句以首先删除所有现有记录。

如果只希望一个数据集用于所有测试,则可以进一步简化和命名数据集data.sql。如果使用内存数据库(这可能对测试有用),由于Spring Boot将在类路径上自动执行data.sql文件,因此您甚至不需要@Sql批注。

使用DbUnit填充

另一种方法是选择类似DbUnit的框架,该框架允许您以XML格式定义数据集。您可以将其与Spring Test DBUnit结合使用,以更轻松地与Spring集成。

您必须牢记,尽管设置起来不像使用@Sql那样容易,并且您需要了解另一种语言,即用于设置数据集的XML结构。