When adding the org.mockito:mockito-inline dependency to the project some tests get stuck.

It happens when we run a single test class, via IDE or CLI, and we have a static variable inside an inner class, like so:

public class MyClassTestApplicationContext {

   @Test
   public void dontStuck() {
      GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
      beanDefinition.setBeanClass(StuckConfig.myOtherClass.getClass());
      beanDefinition.setSource(StuckConfig.myOtherClass);
      GenericApplicationContext context = new GenericApplicationContext();
      context.registerBeanDefinition("myOtherClass", beanDefinition);
      context.refresh();
   }

   @Test
   public void dontStuckAlso() {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
      context.register(DontStuckConfig.class);
      context.refresh();
      context.getBean(MyOtherClass.class);
   }

   @Test
   public void stuck() {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
      context.register(StuckConfig.class);
      context.refresh();
   }

   @Configuration
   public static class StuckConfig {

      private static final MyOtherClass myOtherClass = Mockito.mock(MyOtherClass.class);

      @Bean
      public MyOtherClass myOtherClass() {
         return myOtherClass;
      }
   }

   @Configuration
   public static class DontStuckConfig {

      private final MyOtherClass myOtherClass = Mockito.mock(MyOtherClass.class);

      @Bean
      public MyOtherClass myOtherClass() {
         return myOtherClass;
      }
   }

}

How to reproduce: Run the MyClassTestApplicationContext tests in the sample. You can make it work by doing one of the following: - Remove the mockito-inline dependency; - Remove the static modifier from the mock - Mock an arbitrary object inside the parent class, like so:

public class MyClassTestApplicationContext {
    private static final Object obj = Mockito.mock(Object.class);
    //... remaining code

Sample: https://github.com/marcusdacoregio/mockito-inline-stuck-bug There's a minimum setup in the sample to simulate the behavior on the MyClassTestApplicationContext.

Additional information: I could see that the Thread gets stuck at this part of the ByteBuddyAgent. I first found this problem when running a test class in the Spring Security project, which worked before this change.

Affects: 5.3.8


Comment From: sbrannen

At a glance, this appears to be an issue with either Mockito, ByteBuddy, or a combination of the two.

@marcusdacoregio, what makes you think this has something to do with the core Spring Framework?

Comment From: marcusdacoregio

Thanks for the response @sbrannen. The reason to open the issue within the core framework is because I couldn't simulate the problem without using it. So I thought it would be good to ask help from you.

Comment From: sbrannen

If you annotate StuckConfig with @Configuration(proxyBeanMethods = false), your test will pass.

That ensures that a dynamic subclass of StuckConfig is not created using CGLIB.

I didn't dig into the details, but it appears that mockito-inline is not able to create a mock for the static field when it's inside a subclass generated by CGLIB.

In light of that, I don't consider this an issue for the core Spring Framework.

Please note that mockito-inline is an experimental feature. So please open an issue with the Mockito team to see if they can support such use cases.

Comment From: sbrannen

As a side note, I typically try to avoid static fields in @Configuration classes solely for the purpose of testing. There are usually other options for achieving the same goal within your tests.

Comment From: marcusdacoregio

Thank you @sbrannen. I'll talk with the mockito team about this.