【问题标题】:Spring Boot / Spring Data integration testsSpring Boot / Spring Data 集成测试
【发布时间】:2017-11-28 19:57:19
【问题描述】:

未能配置 Spring Boot 以进行集成测试。冷你请看下面的代码:

实体

@Entity(name = "Item")
@Table(name = "item")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Getter @Setter @NoArgsConstructor
public class Item extends CoreEntity {

    @Embedded
    protected CurrencyAmount amount;

    @Column(name = "operation_time")
    protected ZonedDateTime operationTime;

    @Column(name = "description")
    protected String description;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "category_id")
    protected ItemCategory category;

}



@Entity(name = "Income")
@Table(name = "income")
@Getter @Setter @NoArgsConstructor
public class Income extends Item {

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "budget_id")
    private Budget budget;

    ...

}

存储库

@Repository("incomeDao")
public interface IncomeDao extends JpaRepository<Income, Long> {
}

测试配置

@Configuration
@EnableJpaRepositories(basePackages = "dao.item")
@EntityScan(basePackages = {"model"})
@PropertySource("classpath:application.properties")
@EnableTransactionManagement
public class DaoTestConfiguration {

    @Autowired
    private Environment environment;

    public DataSource getDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getProperty("spring.datasource.driver-class-name"));
        dataSource.setUrl(environment.getProperty("spring.datasource.url"));
        dataSource.setUsername(environment.getProperty("spring.datasource.username"));
        dataSource.setPassword(environment.getProperty("spring.datasource.password"));
        return dataSource;
    }

}

应用程序属性

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa

测试用例

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DaoTestConfiguration.class)
@DataJpaTest
public class IncomeDaoTest {

    @Autowired
    private IncomeDao incomeDao;

    @Test
    public void testSave() {
        Budget budget = Budget.getBulider().setMonth(Month.NOVEMBER).build();
        ItemCategory category = ItemCategory.getBuilder()
                .setItemGroup(ItemGroup.INCOME)
                .setCathegoryName("Salary")
                .build();
        Income income = Income.getBuilder()
                .setBudget(budget)
                .setCurrencyAmount(new CurrencyAmount(Currency.getInstance("USD"), BigDecimal.TEN))
                .setDescription("Monthly salary")
                .setItemCategory(category)
                .setOperationTime(ZonedDateTime.of(2017, 1, 12, 12, 0, 0, 0, ZoneId.of("UTC")))
                .build();
        incomeDao.save(income);

        assertThat(incomeDao.findAll()).containsExactly(income);
    }
}

我尝试了不同的配置(它的最后一个版本),但总是遇到同样的异常:

Caused by: org.h2.jdbc.JdbcSQLException: Таблица "INCOME" не найдена
Table "INCOME" not found; SQL statement:
insert into income (model/amount, currency, category_id, description, operation_time, budget_id, id) values (?, ?, ?, ?, ?, ?, ?) [42102-196]

更多异常的性质是奇怪的,因为它的主要思想是让 Spring Boot 根据实体注释自动生成模式。因此,在插入的那一刻,弹簧必须创建表,但看起来它没有。如果有人告诉我我做错了什么,或者如果有人已经面临这样的问题 - 请让我知道。谢谢。

【问题讨论】:

  • @SpringBootTest@DataJpaTest 基本上是互斥的。您要么想要一个完整的测试@SpringBootTest,要么想要一个切片,但不能两者兼而有之。此外,您正在努力使用 @Configuration 类解决 Spring Boot 问题,Spring Boot 尚未为您配置任何内容。使用不在它周围的框架。
  • 谢谢,但没有成功。我同意 Spring Boot 的配置应该很小,因为 Boot 本身代表自动配置,但我在官方文档或谷歌搜索中找到的所有自动配置都不适合。
  • Spring Boot 已经为您完成了该配置中的所有内容...它没有添加任何内容..
  • 同意。根据示例@DataJpaTest 应该足够了(考虑到 spring-boot-starter-data-jpa、spring-boot-starter-test 和 h2 在 pom 中没有版本),但我得到:Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) 。问题可能出在启动依赖项中吗?
  • 如果没有找到 @SpringBootConfiguration 带注释的类,则意味着它找不到您的 @SpringBootApplication 带注释的类。这通常是由于奇怪的包装造成的(即从您发布的@Configuration 来看,没有像您这样的共享根包)。

标签: java spring-boot spring-data integration-testing


【解决方案1】:

使用@SpringBootTest(完全加载的上下文)或使用@DataJpaTest(JPA 上下文)。

来自documentation

可以结合使用的注解 @RunWith(SpringRunner.class) 用于典型的 JPA 测试。可以在什么时候使用 测试只关注 JPA 组件。

...

如果您希望加载完整的应用程序配置,但 使用嵌入式数据库,你应该考虑结合@SpringBootTest 使用@AutoConfigureTestDatabase 而不是这个注解。

此外,通过在测试类中指定 DaoTestConfiguration 作为配置类:

@SpringBootTest(classes = DaoTestConfiguration.class)

您不依赖于 Spring boot 提供的嵌入式数据库的默认值 在 DaoTestConfiguration 中,您声明了 bean:

public DataSource getDataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(environment.getProperty("spring.datasource.driver-class-name"));
    dataSource.setUrl(environment.getProperty("spring.datasource.url"));
    dataSource.setUsername(environment.getProperty("spring.datasource.username"));
    dataSource.setPassword(environment.getProperty("spring.datasource.password"));
    return dataSource;
}

要么不创建此数据源,而是让 Spring Boot 完成创建它的工作,要么在数据源 bean 声明中同时指定属性 spring.jpa.hibernate.ddl-auto

【讨论】:

  • 谢谢,但如果我删除 @DataJpaTest 则会得到:java.lang.IllegalArgumentException: At least one JPA metamodel must be present!。如果删除 @SpringBootTest(classes = DaoTestConfiguration.class) 则:Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
  • 可能是因为DaoTestConfiguration 没有指定@EnableAutoConfiguration。所以找不到实体。另外,根据DaoTestConfiguration所在的包,搜索bean候选的默认包会发生变化。你真的需要使用DaoTestConfiguration 吗?只需将其删除,否则请确保您指定正确且最小的 Spring Boot 配置。
【解决方案2】:

在 application.properties 中添加这个属性

spring.jpa.hibernate.ddl-auto=update

【讨论】:

  • 已添加,但没有帮助
【解决方案3】:

如果你想做@DataJpaTest,我的回答类似于Bhusan Umiyal,但使用create 而不是update

spring.jpa.hibernate.ddl-auto=create

就像这里的其他人所说的那样,不要将它与@SpringBootTest 一起使用。

还要确保您的测试类与主 Spring Boot 应用程序类位于相同或子包中。

【讨论】:

    猜你喜欢
    • 2020-02-25
    • 1970-01-01
    • 2017-09-22
    • 2015-08-20
    • 2020-04-24
    • 2017-10-27
    • 1970-01-01
    • 2017-04-27
    • 2018-11-19
    相关资源
    最近更新 更多