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

Spring Boot PostgreSQL JPA Repository单元测试Redis连接异常求助

问题:Spring Boot Repository测试中Redis连接失败异常

现有配置与代码

Docker Compose PostgreSQL配置

cmj-postgres:
  image: postgres:15  # 使用PostgreSQL最新稳定版
  container_name: cmj-postgres
  environment:
    POSTGRES_USER: app_admin
    POSTGRES_PASSWORD: application1
    POSTGRES_DB: auth_db
  ports:
    - "5432:5432"
  volumes:
    - postgres_data:/var/lib/postgresql/data  # 持久化数据
    - ./script/init.sql:/docker-entrypoint-initdb.d/init.sql  # 初始化脚本路径
  networks:
    - cmj-network

初始化脚本init.sql

DO $$
    BEGIN
        IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'app_admin') THEN
            CREATE ROLE app_admin WITH LOGIN PASSWORD 'application1';
        END IF;
    END $$;

ServiceRepository接口

@Repository
public interface ServiceRepository extends JpaRepository<Service, Long>
{
    List<Service> findByCategoryIn(List<String> categories);
}

Service实体类

@EqualsAndHashCode(callSuper = true)
@Data
@Entity
@Table(name = "service")
@EntityListeners(AuditingEntityListener.class)
public class Service extends AuditableBaseEntity<String>
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long   id;
    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User   user;
    @NotBlank(message = "Service name is mandatory")
    private String name;
    @NotBlank(message = "Category is mandatory")
    private String category;
    @NotBlank(message = "Subcategory is mandatory")
    private String subcategory;
    @NotBlank(message = "Description is mandatory")
    private String description;
    @NotNull(message = "Pricing model is mandatory")
    private String pricingModel;
    @NotNull(message = "Price is mandatory")
    private Double price;
    private String availability;
    private String deliverables;
    private String requirements;
    private String serviceImage;
    private String serviceVideoLink;
    private String status;
}

单元测试代码

@Testcontainers
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Sql(scripts = "/V1__init.sql")
class ServiceRepositoryTestV1
{
    @Container
    public static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:latest")
        .withDatabaseName("auth_db")
        .withUsername("app_admin")
        .withPassword("application1");
    @Autowired
    private       ServiceRepository      serviceRepository;

    @BeforeEach
    void setUp()
    {
        // 添加测试数据
        Service service1 = new Service();
        service1.setCategory("Category1");
        serviceRepository.save(service1);

        Service service2 = new Service();
        service2.setCategory("Category2");
        serviceRepository.save(service2);
    }

    @Test
    void testFindByCategoryIn()
    {
        List<String> categories = List.of("Category1", "Category2");
        List<Service> services = serviceRepository.findByCategoryIn(categories);

        assertThat(services).hasSize(2);
        assertThat(services).extracting(Service::getCategory)
                            .containsExactlyInAnyOrder("Category1", "Category2");
    }
}

application-test.properties配置

spring.datasource.url=jdbc:tc:postgresql:latest:///auth_db
spring.datasource.username=app_admin
spring.datasource.password=application1
spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

报错信息

Error creating bean with name 'authController' defined in file [E:\Projects\CMJ\cmj-auth\target\classes\com\netsol\cmj\auth\controller\AuthController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'authService' defined in file [E:\Projects\CMJ\cmj-auth\target\classes\com\netsol\cmj\auth\service\AuthService.class]: Unsatisfied dependency expressed through constructor parameter 8: Error creating bean with name 'getRedissonClient' defined in class path resource [com/netsol/cmj/auth/configuration/RedissonConfig.class]: Failed to instantiate [org.redisson.api.RedissonClient]: Factory method 'getRedissonClient' threw exception with message: java.util.concurrent.ExecutionException: org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379
Error creating bean with name 'authService' defined in file [E:\Projects\CMJ\cmj-auth\target\classes\com\netsol\cmj\auth\service\AuthService.class]: Unsatisfied dependency expressed through constructor parameter 8: Error creating bean with name 'getRedissonClient' defined in class path resource [com/netsol/cmj/auth/configuration/RedissonConfig.class]: Failed to instantiate [org.redisson.api.RedissonClient]: Factory method 'getRedissonClient' threw exception with message: java.util.concurrent.ExecutionException: org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379
Caused by: java.util.concurrent.ExecutionException: org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379
    at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
    at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2096)

解决方案

方案1:用Testcontainers启动Redis容器

在测试类中添加Redis容器定义,让Testcontainers自动管理Redis实例:

@Testcontainers
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Sql(scripts = "/V1__init.sql")
class ServiceRepositoryTestV1
{
    @Container
    public static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:latest")
        .withDatabaseName("auth_db")
        .withUsername("app_admin")
        .withPassword("application1");
    
    // 添加Redis容器
    @Container
    public static RedisContainer redisContainer = new RedisContainer(DockerImageName.parse("redis:latest"));

    @Autowired
    private ServiceRepository serviceRepository;

    // 动态设置Redis连接配置
    @DynamicPropertySource
    static void redisProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.redis.host", redisContainer::getHost);
        registry.add("spring.redis.port", redisContainer::getFirstMappedPort);
        // Redisson连接配置
        registry.add("redisson.address", () -> "redis://" + redisContainer.getHost() + ":" + redisContainer.getFirstMappedPort());
    }

    // 剩余测试代码不变
    @BeforeEach
    void setUp() {
        // ...
    }

    @Test
    void testFindByCategoryIn() {
        // ...
    }
}

需在依赖管理中添加Testcontainers Redis依赖:

<!-- Maven -->
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>redis</artifactId>
    <scope>test</scope>
</dependency>

方案2:禁用Redis相关配置(仅测试Repository)

若测试仅需验证Repository功能,可排除Redis相关组件的自动配置:

  1. 修改测试类的@SpringBootTest注解,指定仅扫描Repository相关组件:
@SpringBootTest(classes = {ServiceRepository.class, JpaRepositoriesAutoConfiguration.class})
  1. 或在测试类中排除Redisson配置类:
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Sql(scripts = "/V1__init.sql")
@EnableAutoConfiguration(exclude = RedissonConfig.class)
class ServiceRepositoryTestV1 {
    // ...
}
  1. 或在application-test.properties中添加配置:
# 排除Redisson自动配置
spring.autoconfigure.exclude=com.netsol.cmj.auth.configuration.RedissonConfig

方案3:使用嵌入式Redis

引入嵌入式Redis依赖,测试时自动启动内存Redis:

<!-- Maven -->
<dependency>
    <groupId>it.ozimov</groupId>
    <artifactId>embedded-redis</artifactId>
    <version>0.7.3</version>
    <scope>test</scope>
</dependency>

在测试类中控制嵌入式Redis的启停:

private RedisServer redisServer;

@BeforeEach
void setUp() {
    redisServer = new RedisServer(6379);
    redisServer.start();
    // 其他初始化代码
}

@AfterEach
void tearDown() {
    redisServer.stop();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:44:52