@Test
  public void testRecommender() throws Exception {
    MutableInt recommendCount = new MutableInt();
    Recommender mockRecommender = new MockRecommender(recommendCount);

    Recommender cachingRecommender = new CachingRecommender(mockRecommender);
    cachingRecommender.recommend(1, 1);
    assertEquals(1, recommendCount.intValue());
    cachingRecommender.recommend(2, 1);
    assertEquals(2, recommendCount.intValue());
    cachingRecommender.recommend(1, 1);
    assertEquals(2, recommendCount.intValue());
    cachingRecommender.recommend(2, 1);
    assertEquals(2, recommendCount.intValue());
    cachingRecommender.refresh(null);
    cachingRecommender.recommend(1, 1);
    assertEquals(3, recommendCount.intValue());
    cachingRecommender.recommend(2, 1);
    assertEquals(4, recommendCount.intValue());
    cachingRecommender.recommend(3, 1);
    assertEquals(5, recommendCount.intValue());

    // Results from this recommend() method can be cached...
    IDRescorer rescorer = NullRescorer.getItemInstance();
    cachingRecommender.refresh(null);
    cachingRecommender.recommend(1, 1, rescorer);
    assertEquals(6, recommendCount.intValue());
    cachingRecommender.recommend(2, 1, rescorer);
    assertEquals(7, recommendCount.intValue());
    cachingRecommender.recommend(1, 1, rescorer);
    assertEquals(7, recommendCount.intValue());
    cachingRecommender.recommend(2, 1, rescorer);
    assertEquals(7, recommendCount.intValue());

    // until you switch Rescorers
    cachingRecommender.recommend(1, 1, null);
    assertEquals(8, recommendCount.intValue());
    cachingRecommender.recommend(2, 1, null);
    assertEquals(9, recommendCount.intValue());

    cachingRecommender.refresh(null);
    cachingRecommender.estimatePreference(1, 1);
    assertEquals(10, recommendCount.intValue());
    cachingRecommender.estimatePreference(1, 2);
    assertEquals(11, recommendCount.intValue());
    cachingRecommender.estimatePreference(1, 2);
    assertEquals(11, recommendCount.intValue());
  }
 @Override
 public Void call() throws TasteException {
   for (Preference realPref : prefs) {
     float estimatedPreference = Float.NaN;
     try {
       estimatedPreference = recommender.estimatePreference(testUserID, realPref.getItemID());
     } catch (NoSuchUserException nsue) {
       // It's possible that an item exists in the test data but
       // not training data in which case
       // NSEE will be thrown. Just ignore it and move on.
       log.info("User exists in test data but not training data: {}", testUserID);
     } catch (NoSuchItemException nsie) {
       log.info("Item exists in test data but not training data: {}", realPref.getItemID());
     }
     if (Float.isNaN(estimatedPreference)) {
       noEstimateCounter.incrementAndGet();
     } else {
       estimatedPreference = capEstimatedPreference(estimatedPreference);
       processOneEstimate(estimatedPreference, realPref);
     }
   }
   return null;
 }