如何通过 Mockito.mockStatic(SpringUtils.class) 模拟 SpringUtils.getBean("beanName")

How to mock SpringUtils.getBean("beanName") by Mockito.mockStatic(SpringUtils.class)

当我尝试使用 Mockito 3.7.7 模拟像 SpringUtils.getBean("BeanName") 这样的静态方法时,我得到了 applicationContext 的 NullPointerException,并且 getBean("BeanName") 方法似乎仍然存在已执行,这是我的代码:

public  class SpringUtils implements  ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        // NullPointerException here
        return (T) applicationContext.getBean(name);
    }
}

这是我使用 SpringUtils 的地方:

public class Aaa{
    public Integer getSpringBean(){
        RedisTemplate<String,Object> redisTemplate = SpringUtils.getBean("abc");
        System.out.println(1234);
        return 5;
    }
}

测试代码为:

@Test
public void test(){

        Aaa a = new Aaa();
        try (MockedStatic<SpringUtils> theMock1 = Mockito.mockStatic(SpringUtils.class)) {
            theMock1.when(()->SpringUtils.getBean(Mockito.anyString())).thenReturn(Mockito.mock(RedisTemplate.class));
        }
        Integer x = a.getSpringBean();
        System.out.println(x);
    }

然后我得到一个 NullPointerException:

java.lang.NullPointerException
    at com.labs.common.idgenerator.utils.SpringUtils.getBean(SpringUtils.java:42)
    at com.labs.common.idgenerator.config.Aaa.getSpringBean(Aaa.java:24)

那么,如何使用 mockito 正确模拟 SpringUtils.getBean("beanName")?

此致!

您正在使用 try-with-resources 块来管理您的 MockedStatic。 这意味着 MockedStatic 对象在进入此块时创建,但在退出块时资源自动关闭。

看看MockedStatic.close()

Releases this static mock and throws a MockitoException if closed already.

必须在 MockedStatic 仍处于活动状态时完成与存根静态方法的所有交互 - 在 try-with-resources 块的范围内:


try (MockedStatic<SpringUtils> theMock1 = Mockito.mockStatic(SpringUtils.class)) {
    theMock1.when(()->SpringUtils.getBean(Mockito.anyString()))
            .thenReturn(Mockito.mock(RedisTemplate.class));
    Aaa a = new Aaa();
    Integer x = a.getSpringBean();
    System.out.println(x);
}   

我作为伙伴尝试了代码,它工作正常,但我不太确定它是不是一个好的解决方案:

    @Test
    public void test(){
        CodeRuleConfig config = null;
        try(
            //spring utils
            MockedStatic spring = mockStatic(SpringUtils.class);
            //config center, depends on SpringUtils
            MockedStatic gaea = mockStatic(GaeaUtils.class);
            //RedisUtils, depends on SpringUtils
            MockedStatic redis = mockStatic(RedisUtils.class)
        ){
            spring.when(()->SpringUtils.getBean(Environment.class)).thenReturn(MockData.mockEnv());
            gaea.when(()->GaeaUtils.getCodeRuleConfig(Mockito.anyString())).thenReturn(MockData.getCodeRuleConfig());
            redis.when(()->RedisUtils.hIncrBy(Mockito.anyString(),Mockito.any(),Mockito.anyLong())).thenReturn(999L);
                    System.out.println(IdGenerator.getInstance().nextCode("orderNo"));

        }
    }