Spring Boot 2集成嵌入式PostgreSQL测试报JPA元模型缺失错误
Fixing "At least one JPA metamodel must be present" Error with Embedded PostgreSQL in Spring Boot 2 Tests
It looks like your test setup is missing proper configuration to let Spring detect JPA entities and generate their metamodels, which is why you're hitting that error. Let's break down the issues in your current test code and fix them step by step.
Key Issues in Your Current Test
- Your test class code is incomplete (the
@Autowiredline cuts off), but more importantly: - You're not properly wiring the embedded PostgreSQL instance as the data source for your test context, so Spring might still be trying to use your production PostgreSQL config (or failing to find a valid data source entirely).
- The necessary JPA configuration annotations aren't ensuring Spring scans your entity and repository packages, leading to missing metamodels.
Step-by-Step Solution
1. Complete and Adjust the Test Class
Here's a full, working test class that correctly configures the embedded PostgreSQL and ensures JPA metamodels are detected:
package org.myorg.project.repository; import com.opentable.db.postgres.junit.EmbeddedPostgresRules; import com.opentable.db.postgres.junit.SingleInstancePostgresRule; import org.myorg.project.domain.SomeEntity; import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.PlatformTransactionManager; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.sql.SQLException; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SomeEntityRepositoryTest.TestConfig.class) public class SomeEntityRepositoryTest { @ClassRule public static SingleInstancePostgresRule embeddedPostgres = EmbeddedPostgresRules.singleInstance(); @Autowired private SomeEntityRepository someEntityRepository; @Test public void testSaveAndRetrieveEntity() { // Given SomeEntity entity = new SomeEntity(); entity.setSomeValue("Test Value"); // When SomeEntity savedEntity = someEntityRepository.save(entity); SomeEntity retrievedEntity = someEntityRepository.findById(savedEntity.getId()).orElse(null); // Then assertThat(retrievedEntity).isNotNull(); assertThat(retrievedEntity.getSomeValue()).isEqualTo("Test Value"); } @Configuration @EntityScan(basePackages = "org.myorg.project.domain") @EnableJpaRepositories(basePackages = "org.myorg.project.repository") static class TestConfig { @Bean public DataSource dataSource() throws SQLException { // Wire the embedded PostgreSQL instance as the test data source return embeddedPostgres.getEmbeddedPostgres().getPostgresDatabase(); } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); em.setPackagesToScan("org.myorg.project.domain"); // Explicitly scan entity package em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); return em; } @Bean public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(emf); return transactionManager; } } }
2. Key Fixes Explained
- Dedicated Test Configuration: The inner
TestConfigclass isolates test-specific setup, ensuring we use the embedded PostgreSQL instead of production config. - Explicit Scanning:
@EntityScanand@EnableJpaRepositoriestell Spring exactly where to find your entities and repositories, which guarantees JPA metamodels are generated and detected. - JPA Initialization: We manually configure the entity manager factory and transaction manager to ensure JPA is fully set up in the test context, eliminating the metamodel missing error.
- Isolated Context: Using
@ContextConfigurationinstead of a full@SpringBootTestkeeps tests fast by only loading the necessary beans, but if you prefer@SpringBootTest, you can override the data source properties dynamically:@SpringBootTest(properties = { "spring.datasource.url=jdbc:postgresql://localhost:" + embeddedPostgres.getPort() + "/postgres", "spring.datasource.username=postgres", "spring.datasource.password=" })
3. Additional Checks
- Lombok in Tests: Ensure your build tool (Maven/Gradle) processes Lombok annotations for test classes. For Maven, confirm the Lombok plugin includes test sources in its configuration.
- Dependency Compatibility: Verify
otj-pg-embedded:0.12.0works with your Spring Boot 2 version. If you hit compatibility issues, try upgrading to a newer version ofotj-pg-embeddedthat aligns with your Spring Boot release.
内容的提问来源于stack exchange,提问作者hlepme
相关产品推荐
相关产品推荐

