具有本机查询的存储库在测试环境中失败 - postgres、jpa、spring
Repositories with native queries fail in test environment - postgres, jpa, spring
我已经使用测试容器为 spring 引导项目设置了集成测试(使用 postgresql 设置了 docker 实例)。如果我正在测试的存储库不使用本机查询,则测试效果很好。但是,每当存储库包含本机查询时,我都会收到以下错误:ERROR: relation "my_table_here" does not exist
。如何让我的测试配置工作以允许本机查询?
下面是我的测试设置:
@RunWith(SpringRunner.class)
public class TestPostgresql {
@ClassRule
public static PostgreSQLContainer postgreSQLContainer = PostgresDbContainer.getInstance();
/**
* ************ REPOSITORIES ************
*/
@Autowired
NativeQueryRepository nativeQueryRepository;
@TestConfiguration
@EnableJpaAuditing
@EnableJpaRepositories(
basePackageClasses = {
NativeQueryRepository.class
})
@ComponentScan(
basePackages = {
"com.company.project.package.repository"
}
)
static class PostgresConfiguration {
/**
* ************ DATABASE SETUP ************
*/
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(postgreSQLContainer.getJdbcUrl());
dataSource.setUsername(postgreSQLContainer.getUsername());
dataSource.setPassword(postgreSQLContainer.getPassword());
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new JpaVendorAdapter();
vendorAdapter.setDatabase(Database.POSTGRESQL);
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.company.project");
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
}
编辑:我认为这与命名策略有关?
这里有一个关于如何在存储库中使用 nativeQuery 的示例
@Repository
public interface NativeQueryRepository extends JpaRepository<NativeEvent, Long> {
@Modifying
@Transactional
@Query(value = "UPDATE native_event SET state = :state " +
"WHERE secondary_id = :secondaryId", nativeQuery = true)
void updateState(
@Param("state") String state,
@Param("secondaryId") String secondaryId);
}
我还尝试通过添加注释更新 TestPostgresql
内静态 class 的 testProperties:
@TestPropertySource(properties = {
"spring.jpa.hibernate.naming-strategy=org.springframework.boot.orm.jpa.SpringNamingStrategy"
})
但是,收到的错误没有任何变化。
编辑:添加 NativeEvent
:
@Entity
@Table(
name = "NativeEvent",
indexes = {
@Index(name = "idx_native_event_secondary_id", columnList = "secondaryId")
}
)
@EntityListeners(AuditingEntityListener.class)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class NativeEvent implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="secondaryId", nullable=false)
private String secondaryId;
@Column(name="state")
private String state;
}
您明确指定您的 table 名称,如下所示:
@Table(name = "NativeEvent")
但在您的本机查询中您有不同的名称 table:
@Query(value = "UPDATE native_event ...)
从您的 @Table
注释中删除 name
属性(假设您的命名策略会产生类似 native_event 的名称)或更改 table 本机查询中的名称为 nativeevent 或 nativeEvent 所以在这种情况下只需删除下划线。
有点相关post
您正在进行手动配置,而不是使用运行时配置。因此,命名策略的处理方式不同。相反,您应该重用相同的配置而不是编写自己的配置。
使用 @SpringBootTest
或 @DataJpaTest
,并且仅 re-configure DataSource
。
用 ApplicationContextInitializer
做一些事情,将 JDBC 属性放入 ApplicationContext
。
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(initializers = {TestPostgresql.JdbcInitializer.class})
public class TestPostgresql {
@ClassRule
public static PostgreSQLContainer postgreSQLContainer = PostgresDbContainer.getInstance();
/**
* ************ REPOSITORIES ************
*/
@Autowired
NativeQueryRepository nativeQueryRepository;
static class JdbcInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues.of(
"spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
"spring.datasource.username=" + postgreSQLContainer.getUsername(),
"spring.datasource.password=" + postgreSQLContainer.getPassword()
).applyTo(configurableApplicationContext.getEnvironment());
}
}
}
这将在您的测试中重用运行时的配置。除了 @SpringBootTest
,您还应该能够使用 @DataJpaTest(NativeQueryRepository.class)
来仅对 JPA 进行切片测试。
我已经使用测试容器为 spring 引导项目设置了集成测试(使用 postgresql 设置了 docker 实例)。如果我正在测试的存储库不使用本机查询,则测试效果很好。但是,每当存储库包含本机查询时,我都会收到以下错误:ERROR: relation "my_table_here" does not exist
。如何让我的测试配置工作以允许本机查询?
下面是我的测试设置:
@RunWith(SpringRunner.class)
public class TestPostgresql {
@ClassRule
public static PostgreSQLContainer postgreSQLContainer = PostgresDbContainer.getInstance();
/**
* ************ REPOSITORIES ************
*/
@Autowired
NativeQueryRepository nativeQueryRepository;
@TestConfiguration
@EnableJpaAuditing
@EnableJpaRepositories(
basePackageClasses = {
NativeQueryRepository.class
})
@ComponentScan(
basePackages = {
"com.company.project.package.repository"
}
)
static class PostgresConfiguration {
/**
* ************ DATABASE SETUP ************
*/
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(postgreSQLContainer.getJdbcUrl());
dataSource.setUsername(postgreSQLContainer.getUsername());
dataSource.setPassword(postgreSQLContainer.getPassword());
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new JpaVendorAdapter();
vendorAdapter.setDatabase(Database.POSTGRESQL);
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.company.project");
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
}
编辑:我认为这与命名策略有关?
这里有一个关于如何在存储库中使用 nativeQuery 的示例
@Repository
public interface NativeQueryRepository extends JpaRepository<NativeEvent, Long> {
@Modifying
@Transactional
@Query(value = "UPDATE native_event SET state = :state " +
"WHERE secondary_id = :secondaryId", nativeQuery = true)
void updateState(
@Param("state") String state,
@Param("secondaryId") String secondaryId);
}
我还尝试通过添加注释更新 TestPostgresql
内静态 class 的 testProperties:
@TestPropertySource(properties = {
"spring.jpa.hibernate.naming-strategy=org.springframework.boot.orm.jpa.SpringNamingStrategy"
})
但是,收到的错误没有任何变化。
编辑:添加 NativeEvent
:
@Entity
@Table(
name = "NativeEvent",
indexes = {
@Index(name = "idx_native_event_secondary_id", columnList = "secondaryId")
}
)
@EntityListeners(AuditingEntityListener.class)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class NativeEvent implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="secondaryId", nullable=false)
private String secondaryId;
@Column(name="state")
private String state;
}
您明确指定您的 table 名称,如下所示:
@Table(name = "NativeEvent")
但在您的本机查询中您有不同的名称 table:
@Query(value = "UPDATE native_event ...)
从您的 @Table
注释中删除 name
属性(假设您的命名策略会产生类似 native_event 的名称)或更改 table 本机查询中的名称为 nativeevent 或 nativeEvent 所以在这种情况下只需删除下划线。
有点相关post
您正在进行手动配置,而不是使用运行时配置。因此,命名策略的处理方式不同。相反,您应该重用相同的配置而不是编写自己的配置。
使用 @SpringBootTest
或 @DataJpaTest
,并且仅 re-configure DataSource
。
用 ApplicationContextInitializer
做一些事情,将 JDBC 属性放入 ApplicationContext
。
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(initializers = {TestPostgresql.JdbcInitializer.class})
public class TestPostgresql {
@ClassRule
public static PostgreSQLContainer postgreSQLContainer = PostgresDbContainer.getInstance();
/**
* ************ REPOSITORIES ************
*/
@Autowired
NativeQueryRepository nativeQueryRepository;
static class JdbcInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues.of(
"spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
"spring.datasource.username=" + postgreSQLContainer.getUsername(),
"spring.datasource.password=" + postgreSQLContainer.getPassword()
).applyTo(configurableApplicationContext.getEnvironment());
}
}
}
这将在您的测试中重用运行时的配置。除了 @SpringBootTest
,您还应该能够使用 @DataJpaTest(NativeQueryRepository.class)
来仅对 JPA 进行切片测试。