mockito 模拟静态方法在java中没有按预期工作

mkshixfv  于 9个月前  发布在  Java
关注(0)|答案(1)|浏览(84)

我有课

public class MyMainClass{
    
    public void mainLogic(){
     handleEvictedKeys( key, value, removalCause)
}

    private void handleEvictedKeys(final Object key, final Object value, final RemovalCause removalCause) {
        if (removalCause.equals(RemovalCause.SIZE)) {
            remote.setOrReplaceValueForKey((String) key, (Map<String, String>) value);
        } else {
            log.warn("Key {} and Value {} was evicted from cache for theme {} for the reason {}", key, value,
                cacheInformation.getThemeName(), removalCause);
        }
    }

        GenericCacheBuilder genericCacheBuilder = CacheSystemToCacheManagerProvider
            .getCacheBuilder(cacheInformation.getRemoteCachePreference());
        return (RemoteCacheManager) genericCacheBuilder.buildCacheManager(cacheInformation);
    }
}

我的远程提供商

public class CacheSystemToCacheManagerProvider {

        private static final ImmutableMap<AllowedCacheSystem, GenericCacheBuilder<?>> CACHE_SYSTEM_TO_CACHE_BUILDER_MAP =
            ImmutableMap.<AllowedCacheSystem, GenericCacheBuilder<?>>builder()
                .put(AllowedLocalCacheSystem.COMMON_CAFFEINE, new CommonCaffeineCacheBuilder())
                .put(AllowedRemoteCacheSystem.COMMON_REDIS, new CommonRedisCacheBuilder())
                .build();
    
    
        public static GenericCacheBuilder getCacheBuilder(AllowedCacheSystem cacheSystem) {
            return CACHE_SYSTEM_TO_CACHE_BUILDER_MAP.get(cacheSystem);
        }
    }

当我尝试为MyMainClass编写单元测试时,

public class TestMyMainClass(){

//all dependencies
@InjectMocks
public MyMainClass mtestClass;

public void mymainLogic(){

        cacheSystemToCacheManagerProviderStatic = Mockito.mockStatic(CacheSystemToCacheManagerProvider.class);
        cacheSystemToCacheManagerProviderStatic.when(
                CacheSystemToCacheManagerProvider::getCacheBuilder)
            .thenReturn(getCacheBuilderMock);
mtestClass.handleEvictedKeys(a,b,c)
}

}

我试图模拟调用CacheSystemToCacheManagerProvider.getCacheBuilder(),但这是在进行实际调用,并试图创建new CommonCaffeineCacheBuilder()的示例,这会带来很多依赖关系并破坏UT。
如何正确模拟此静态调用

00jrzges

00jrzges1#

new CommonCaffeineCacheBuilder()的调用不会在执行getCacheBuilder时发生。它发生在该点之前,在加载CacheSystemToCacheManagerProvider类时立即执行的静态初始化器中。在有机会嘲笑它之前,这必然会发生。
更好的设计将使CacheSystemToCacheManagerProviderMyMainClass中 * 可替换 *,使其更容易被模仿:

public class MyMainClass{
    private final CacheSystemToCacheManagerProvider cacheSystemToCacheManagerProvider;

    public MyMainClass(CacheSystemToCacheManagerProvider cacheSystemToCacheManagerProvider) {
        this.cacheSystemToCacheManagerProvider = cacheSystemToCacheManagerProvider;
    }

    public String myLogic(CacheInformation cacheInformation){
        return getRemoteCacheManager(cacheInformation).getValueForKey("some string");
    }

    public RemoteCacheManager getRemoteCacheManager(CacheInformation cacheInformation) {
        GenericCacheBuilder<?> genericCacheBuilder = cacheSystemToCacheManagerProvider
                .getCacheBuilder(cacheInformation.getRemoteCachePreference());
        return (RemoteCacheManager) genericCacheBuilder.buildCacheManager(cacheInformation);
    }
}
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class TestMyMainClass {
    @Test
    public void myLogicTest() {
        var mockCacheSystemToCacheManagerProvider = mock(CacheSystemToCacheManagerProvider.class);
        var mockCacheBuilder = mock(GenericCacheBuilder.class);
        var mockCacheManager = mock(RemoteCacheManager.class);
        var mockCacheInformation = mock(CacheInformation.class);

        when(mockCacheSystemToCacheManagerProvider.getCacheBuilder(any())).thenReturn(mockCacheBuilder);
        when(mockCacheBuilder.buildCacheManager(any())).thenReturn(mockCacheManager);
        when(mockCacheManager.getValueForKey("some string")).thenReturn("some value");

        MyMainClass myMainClass = new MyMainClass(mockCacheSystemToCacheManagerProvider);
        assertEquals("some value", myMainClass.myLogic(mockCacheInformation));
    }

}

关键是使CacheSystemToCacheManagerProvider成为一个 * 接口 *:

public interface CacheSystemToCacheManagerProvider {
    GenericCacheBuilder<?> getCacheBuilder(AllowedCacheSystem system);
}

对于使用真实的缓存提供程序的 * 实现 *:

public class StandardCacheSystemToCacheManagerProvider implements CacheSystemToCacheManagerProvider {

    private final ImmutableMap<AllowedCacheSystem, GenericCacheBuilder<?>> CACHE_SYSTEM_TO_CACHE_BUILDER_MAP =
            ImmutableMap.<AllowedCacheSystem, GenericCacheBuilder<?>>builder()
                    .put(AllowedLocalCacheSystem.COMMON_CAFFEINE, new CommonCaffeineCacheBuilder())
                    .put(AllowedRemoteCacheSystem.COMMON_REDIS, new CommonRedisCacheBuilder())
                    .build();

    @Override
    public GenericCacheBuilder<?> getCacheBuilder(AllowedCacheSystem cacheSystem) {
        return CACHE_SYSTEM_TO_CACHE_BUILDER_MAP.get(cacheSystem);
    }
}

这确保了在测试中不会创建CommonCaffeineCacheBuilderCommonRedisCacheBuilder示例。

相关问题