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相关组件的自动配置:
- 修改测试类的
@SpringBootTest注解,指定仅扫描Repository相关组件:
@SpringBootTest(classes = {ServiceRepository.class, JpaRepositoriesAutoConfiguration.class})
- 或在测试类中排除Redisson配置类:
@SpringBootTest @ActiveProfiles("test") @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Sql(scripts = "/V1__init.sql") @EnableAutoConfiguration(exclude = RedissonConfig.class) class ServiceRepositoryTestV1 { // ... }
- 或在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
相关产品推荐
相关产品推荐

