Spring Boot 2.2.5.RELEASE

Mocking a @Cacheable method with @SpyBean results in null when calling method. Example:

@Service
public class SomeService{
    @Cacheable("somecache")
    public String method() {
        return "not";
    }
}
@SpringBootTest
@TestExecutionListeners(MockitoTestExecutionListener.class)
public class TestClass extends AbstractTestNGSpringContextTests {
    @SpyBean SomeService spybean;

    @Test
    public void test(){
       doReturn( "expected" ).when( spybean ).method();
       assertEquals( spybean.method(), "expected" ); //fails
    }
}

Comment From: wilkinsona

Having copied those two classes into a minimal sample application configured to use TestNG, I cannot reproduce the problem. If you would like us to spend some more time investigating, please spend some time providing a complete and minimal sample that reproduces the problem. You can share it with us by zipping it up and attaching it to this issue or by pushing it to a separate repository on GitHub.

Comment From: cdalexndr

https://github.com/cdalexndr/spring-boot-issue-20426 just run gradlew test I forgot to mention that I'm using aspectj. It may fail only when using aspectj mode.

Comment From: mbhave

Another SpyBean issue that might be related: spring-projects/spring-framework#24724

Comment From: wilkinsona

Thanks for the sample. As @mbhave suspected, this appears to be very similar to https://github.com/spring-projects/spring-framework/issues/24724. Here's a sample that reproduces the problem without any involvement from Spring Boot:

package example;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = Application.class)
public class SomeServiceTest {

    @Spy
    SomeService someService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testCacheable() {
        doReturn("yes").when(someService).cacheableMethod();
        assertThat(someService.cacheableMethod()).isEqualTo("yes");
    }

    @Test
    public void testNormal() {
        doReturn("yes").when(someService).normalMethod();
        assertThat(someService.normalMethod()).isEqualTo("yes");
    }

}

@Service
class SomeService {

    @Cacheable("someCache")
    public String cacheableMethod() {
        return "not";
    }

    public String normalMethod() {
        return "not";
    }
}

@ComponentScan
@Configuration
@EnableCaching(mode = AdviceMode.ASPECTJ)
class Application {

    @Bean
    ConcurrentMapCacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }

}
plugins {
    id 'org.springframework.boot' version '2.2.5.RELEASE'
}
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'

repositories {
    mavenCentral()
}

dependencies {
    implementation group: 'org.aspectj', name: 'aspectjweaver'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-aop'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web'
    implementation 'org.springframework:spring-aspects'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    File springAgent = configurations.runtimeClasspath.filter { f -> f.name.matches("aspectjweaver.*\\.jar") }.iterator().next();
    jvmArgs += ["-javaagent:" + springAgent.absolutePath]
}

Comment From: snicoll

Closing as a duplicate of https://github.com/spring-projects/spring-framework/issues/24724. I'll drop a note there to make sure to review the reproducer above.