0

我们有很多带有连接和提取的方法,如下所示:

@Query(
        "select new com.company.user.entity.DTO.UserBillingDTO(" +
                    "u.id as id, " +
                    "u.firstName as firstName, " +
                    "u.lastName as lastName, " +
                    "e.tokenId as tokenId," +
                    "u.companyId as companyId," +
                    "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 查询是否返回了预期的结果。

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

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

你能想到别的吗?我如何编写一个易于团队遵循的可维护测试套件?

编辑:

4

2 回答 2

2

使用存储库填充

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

@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.sqlsrc/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 结构。

于 2018-07-19T09:46:11.607 回答
1

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

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

您可以按照81.5 使用高级数据库迁移工具一章使用 Flyway 或 Liquibase 填充数据库。根据文档:

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

于 2018-07-19T09:23:11.973 回答