You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

  1. Your test class code is incomplete (the @Autowired line cuts off), but more importantly:
  2. 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).
  3. 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 TestConfig class isolates test-specific setup, ensuring we use the embedded PostgreSQL instead of production config.
  • Explicit Scanning: @EntityScan and @EnableJpaRepositories tell 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 @ContextConfiguration instead of a full @SpringBootTest keeps 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.0 works with your Spring Boot 2 version. If you hit compatibility issues, try upgrading to a newer version of otj-pg-embedded that aligns with your Spring Boot release.

内容的提问来源于stack exchange,提问作者hlepme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:03:55