1

我的缓存配置如下;

@Configuration
public class CacheConfiguration {

    @Bean
    public CacheManager cacheManager(Ticker ticker) {
        CaffeineCache bookCache = buildCache("books", ticker, 30);
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Collections.singletonList(bookCache));
        return cacheManager;
    }

    private CaffeineCache buildCache(String name, Ticker ticker, int minutesToExpire) {
        return new CaffeineCache(name, Caffeine.newBuilder()
                .expireAfterWrite(minutesToExpire, TimeUnit.MINUTES)
                .maximumSize(100)
                .ticker(ticker)
                .build());
    }

    @Bean
    public Ticker ticker() {
        return Ticker.systemTicker();
    }
}

我要测试的服务:

@Service
public class TestServiceImpl implements TestService {

    private final BookRepository bookRepository; // interface

    @Autowired
    public TestServiceImpl(final BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @Override
    public Book getByIsbn(String isbn) {
        return bookRepository.getByIsbn(isbn);
    }
}

存储库中所需的方法用@Cacheable("books").

@Override
@Cacheable("books")
public Book getByIsbn(String isbn) {
    LOGGER.info("Fetching Book...");
    simulateSlowService(); //  Wait for 5 secs
    return new Book(isbn, "Some book");
}

我需要编写一个显示缓存工作的测试。所以我ticker在测试中创建了另一个 bean 来覆盖CacheConfiguration. 编码;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestServiceTests {

    private static final String BOOK_ISBN = "isbn-8442";

    @SpyBean
    private BookRepository bookRepository;

    @Autowired
    private TestService testService;

    @Configuration
    @Import(SpringBootCacheApplication.class)
    public static class TestConfiguration {

        //testCompile('com.google.guava:guava-testlib:23.6-jre')
        static FakeTicker fakeTicker = new FakeTicker();

        @Bean
        public Ticker ticker() {
            return fakeTicker::read;
        }
    }

    @Before
    public void setUp() {
        Book book = fakeBook();
        doReturn(book)
                .when(bookRepository)
                .getByIsbn(BOOK_ISBN);
    }

    private Book fakeBook() {
        return new Book(BOOK_ISBN, "Mock Book");
    }

    @Test
    public void shouldUseCache() {
        // Start At 0 Minutes
        testService.getByIsbn(BOOK_ISBN);
        verify(bookRepository, times(1)).getByIsbn(BOOK_ISBN);

        // After 5 minutes from start, it should use cached object
        TestConfiguration.fakeTicker.advance(5, TimeUnit.MINUTES);
        testService.getByIsbn(BOOK_ISBN);
        verify(bookRepository, times(1)).getByIsbn(BOOK_ISBN); // FAILS HERE

        // After 35 Minutes from start, it should call the method again
        TestConfiguration.fakeTicker.advance(30, TimeUnit.MINUTES);
        testService.getByIsbn(BOOK_ISBN);
        verify(bookRepository, times(2)).getByIsbn(BOOK_ISBN);
    }
}

但它在标有//FAILS HERE消息的行处失败;

org.mockito.exceptions.verification.TooManyActualInvocations: simpleBookRepository.getByIsbn("isbn-8442"); Wanted 1 time: -> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) But was 2 times. Undesired invocation: -> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

为什么会失败?它不应该使用缓存吗?还是我的测试错了?

非常感谢任何帮助或指示!:)

4

1 回答 1

0
verify(bookRepository, times(1)).getByIsbn(BOOK_ISBN); // FAILS HERE

当然这里失败了。因为在您已经调用了一次此方法之前 ~4 行。在此检查中,您应该输入times(2). 并且在下一次检查调用次数应该是times(3)

于 2018-06-22T05:09:58.700 回答