import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.TestPropertySource;

@SpringBootTest
@TestPropertySource(properties = "logging.level.root=INFO")
public class ApplicationTests {

    @SpyBean
    private RedisConnectionFactory redisConnectionFactory;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    void test() {
        stringRedisTemplate.opsForValue().set("foo", "bar");
    }

}
$ gradle test

> Task :test
2023-04-28T12:49:50.113+08:00  WARN 31995 --- [ionShutdownHook] d.r.c.l.LettucePoolingConnectionProvider : LettucePoolingConnectionProvider contains unreleased connections

BUILD SUCCESSFUL in 3s
3 actionable tasks: 3 executed

here is minimal test project warning.zip

Comment From: wilkinsona

I don't think this is specific to @SpyBean. The same problem occurs with a direct call to Mockito.spy:

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

@SpringBootTest
@Testcontainers
public class ApplicationTests {

    @Container
    static RedisContainer redis = new RedisContainer();

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DynamicPropertySource
    static void redisProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.redis.host", redis::getHost);
        registry.add("spring.data.redis.port", redis::getFirstMappedPort);
    }

    @Test
    void test() {
        stringRedisTemplate.opsForValue().set("foo", "bar");
    }

    @TestConfiguration
    static class RedisConfiguration {

        @Bean
        static BeanPostProcessor redisConnectionFactorySpy() {
            return new BeanPostProcessor() {

                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    if (bean instanceof LettuceConnectionFactory) {
                        return Mockito.spy(bean);
                    }
                    return bean;
                }

            };
        }

    }

    static class RedisContainer extends GenericContainer<RedisContainer> {

        public RedisContainer() {
            super("redis:4.0.14");
            addExposedPorts(6379);
        }

    }


}

I suspect it's due to an interaction between Mockito and Lettuce. Unfortunately, without any evidence to suggest that the problem's caused by Spring Boot we can't justify spending any more time on investigating the root cause. If you can provide a minimal example that shows the problem is somehow specific to Spring Boot we can re-open the issue and take another look.