@Cacheble和@Mock/@InjectMocks问题

uemypmqf  于 2022-10-22  发布在  Java
关注(0)|答案(1)|浏览(190)

我目前无法在同一测试类中使用*@Cacheble@Mock/@InjectMocks*。
要清楚,因为使用了Mockito。verify(repository,times(1))我需要@Mock存储库并为存储库使用注解*@InjectMock*。这样做,我可以正确地验证应用程序的行为,但findById的结果不会被缓存。事实上,manager.get(cacheName)。get(key)将返回null。
相反,如果我使用
@Autowired
注解,值将被缓存,但verify(存储库,times(1))返回ZeroInteractions。我用调试器进行了检查,结果正常。
我应该如何让缓存存储和verify()都工作?为什么会这样?

  • [我正在使用SpringBoot 2.1.3版本和Caffeine Cache Manager 3.1.1版]*

这是CacheManager类:

@Slf4j
    @Configuration
    @EnableCaching
    public class CaffeineCacheConfig extends CachingConfigurerSupport {

        @Bean("cacheManager")
        public CacheManager cacheManager() {
            SimpleCacheManager cacheManager = new SimpleCacheManager(); 
            cacheManager.setCaches(generateCache());
            return cacheManager;
        }
    }

这是缓存:

@Override
        public CaffeineCache generateCache() {
            return new CaffeineCache(name,
                    Caffeine.newBuilder()
                            .maximumSize(15)
                            .expireAfterWrite(60, TimeUnit.MINUTES)
                            .recordStats()
                            .build());
        }

我有一个我试图缓存的服务,它是这样的:

@Service
@CacheConfig(cacheNames = CacheLocations.APPLICATION_LEVEL)
@Transactional(readOnly = true)
public class ApplicationLevelService implements IApplicationLevelService
{
    @Autowired
    private ApplicationLevelRepository repository;
    @Autowired
    private CacheManager manager;

    @Override
    @Cacheable
    public ApplicationLevel findById(int id)
    {
        return repository.findById(id);
    }
}

我试图用这个类(JUnit5)测试它:

@CacheConfig(cacheNames = {APPLICATION_LEVEL})
class ApplicationLevelCacheTest extends AbstractSpringTest
{
    @InjectMocks
    private ApplicationLevelService service;
    @Mock
    private ApplicationLevelRepository repository;
    @Autowired
    private CacheManager cacheManager;

    @BeforeEach
    void evictCache()
    {
        cacheManager.getCache(APPLICATION_LEVEL).clear();
    }

    @Nested
    class TestApplicationLevelCache
    {
        @Test
        @DisplayName("findAById() sets the resulting list in '" + CacheLocations.APPLICATION_LEVEL + "' cache")
        void testApplicationLevelCaching_ApplicationLevelsAreCached_FindById()
        {
            when(repository.findById(anyInt())).thenReturn(Optional.of(new ApplicationLevel("mocked")));

            assertNotNull(cacheManager.getCache(CacheLocations.APPLICATION_LEVEL));

            var expected = service.findById(1);
            verify(repository, times(1)).findById(anyInt());

            assertNotNull(cacheManager.getCache(APPLICATION_LEVEL).get(1));

            // should be cached
            var actual = service.findById(1);
            verifyZeroInteractions(repository);
            assertEquals(expected, actual);
        }
    }
}

其中AbstractSpringTest只是包含以下内容的类:

  • @SpringJUnitConfig
  • @Spring启动测试()
  • @ActiveProfiles(“测试”)
o4tp2gmn

o4tp2gmn1#

verify()方法可用于验证已与Mockito进行模拟的bean的交互次数。
使用@Autowired注解,您已经通过使用Spring的D.I.直接从Spring容器获取bean来初始化bean。您的cacheManager对象位于Mockito的上下文之外。它并没有被Mockito嘲笑。
我认为可以通过在cacheManager对象上使用@Spy注解来解决这个问题。
@Spy@Mock都可以用于模拟字段。不同之处在于,使用@Mock注解,您可以创建一个完整的模拟或虚拟对象,而使用m1n 8o1p,您可以拥有真实对象,并且可以直接调用或模拟其特定方法。
您可以尝试使用:

@Spy
CacheManager cacheManager = new SimpleCacheManager();

希望能有所帮助。

相关问题