2012-02-13 6 views
3

Я использую Java 6 и Mockito 1.8.5. Я хочу издеваться над методом класса члена, но я не могу понять, как это сделать. У меня есть эти классы ...Как мне высмеять метод поля члена класса?

public class CacheService implements CacheCallback { 

private final Cache cache; 
... 

public static CacheService getInstance() { 
    return INSTANCE; 
} 

private CacheService() { 
    cache = new DefaultCacheImpl(); 
} 

public boolean saveNodes(final Map<Long, XmlNode> nodeMap) { 
    ... 
    cache.saveNodes(nodeMap); 
} 
... 
} 


public class DefaultCacheImpl implements Cache { 
... 
public void saveNodes(Map<Long, XmlNode> xmlNodes) { 
    dao.updateDB(xmlNodes); 
} 
... 
} 

Я не могу понять, как высмеивать метод «Кэш» FIELD-члена «saveNodes». Я насмешливо методы ниже, а потому, что нет сеттера в классе CacheService для поля, я не могу понять, как придать мои издеваться ..

public class PopulateCacheServiceImpl extends RemoteServiceServlet implements PopulateCacheService { 
... 
public Boolean initCache() { 
    boolean ret = false; 
    try { 
     setupMocks(); 
     CacheService.getInstance().startCache(); 
     PopulateCache.addTestEntriesToCache(); 
     ret = true; 
    } catch (Exception e) { 
     e.printStackTrace(System.err); 
     ret = false; 
    } // try 
    return ret; 
} // initCache 

private void setupMocks() { 
    DefaultCacheImpl cache = mock(DefaultCacheImpl.class); 
    doAnswer(new Answer<Object>() { 
     public Object answer(InvocationOnMock invocation) throws Throwable { 
      return null; 
     } 
    }).when(cache).saveNodes(Matchers.anyMap()); 
} // setupMocks 

} 

Есть ли другие способы сделать это с Мокито? Спасибо, - Дэйв

ответ

3

Проблема заключается в этой строке:

cache = new DefaultCacheImpl(); 

Если вы строите объект кэша внутри вашего CacheService, они тесно связаны между собой. Вы не можете использовать CacheService с другой реализацией кэша.

Вместо передать реализацию кэша конструктору:

public CacheService(Cache cacheImpl) { 
    this.cache = cacheImpl; 
} 

Это позволяет CacheService использовать любую реализацию кэша.

+0

Благодарим за это, но CacheService является одноэлементным и в настоящее время имеет частный конструктор. Я могу изменить исходный код, но мне все равно нужен только один экземпляр класса CacheService, плавающего вокруг jvm. – Dave

+2

@Dave Вам следует серьезно подумать о том, чтобы избежать этой статической зависимости от 'CacheService.getInstance()' и использовать правильный DI, поэтому вам не придется взламывать вещи здесь и там, чтобы просто проверить. Ваш дизайн будет намного более чистым и элегантным. – Brice

+0

Я открыт для того, что вы говорите, но наш проект запрещает использование сторонних инструментов (например, Spring) для основного проекта (для проверки его штрафа). Я не в состоянии бороться с политикой своей компании. Как бы вы DI с ситуацией, которую я настраивал, имея в виду, мне нужен только один экземпляр объекта CacheService в JVM? – Dave

1

Если вы можете изменить источник, разберите эти классы. Избавиться от cache = new DefaultCacheImpl(); от конструктора, как предложил Сьёрд.

Если вы не можете использовать PowerMock до mock the constructor от DefaultCacheImpl. Я должен сказать, что это действительно уродливое решение (единственный уродливый издевательский статический код инициализации).

Примечание: Ваш код является ответом на популярный вопрос «Зачем мне нужна инъекция зависимостей?». Я думаю, что люди смотрели на такой код, когда изобрели DI.

+0

Мне нравится идея PowerMock b/c Мне не нужно менять источник. Мой вопрос заключается в том, что я должен использовать аннотацию «PrepareForTest»? Объявление класса выше («PopulateCacheServiceImpl») не является тестовым классом JUnit, а косвенным образом вызвано рядом различных тестов. – Dave

+0

Да, вы должны сделать аннотацию PrepareForTest.Вы также можете использовать PowerMock для издевательства статического метода getInstance() и вернуть макет вместо singleton. Я не думаю, что это помогает с вашей проблемой множественных точек создания. – jhericks

2

Как насчет создания двух конструкторов? Тот, который у вас есть, останется там. Еще один позволит вам перейти в реализацию Cache и позволить вам протестировать класс. Новый конструктор может иметь защищенный доступ для ограничения того, какие классы могут его использовать.

+2

Или пакет-частный, а не защищенный. –

Смежные вопросы