2016-04-16 2 views
0

Im пытается найти лучший способ проверить класс кэша, который в настоящее время используется им ... Я хотел бы заменить ClientFactory ниже, когда этот класс запускается в тестах .... I хотели бы оставить структуру класса как можно больше, но так как он имеет частный конструктор IM борется, чтобы думать, что лучший способ, чтобы проверить его ..Тестирование класса с помощью частного конструктора

public class MyCache { 

private final long TIME_OUT 

private static MyCache instance = null; 

private final HashMap<String, MyObject> cache = new HashMap<String, MyObject>(); 

private MyCache() { 
} 

public static MyCache getInstance() { 
    if (instance == null) { 
     instance = new MyCache(); 
    } 
    return instance; 
} 

public MyObject getDetails(String id) throws Exception { 

    MyObject myObject = cache.get(id); 
    if (myObject != null) { 
     return myObject; 
    } else { 
     try { 

      // want to be able to replace ClientFactory with test stub 
      Client client = ClientFactory.createClient(); 
      myObject = client.getMyObject(id); 

     } catch (NotFoundException nf) { 
      .... log error 
     } 

     return myObject; 
    } 
} 

} 
+2

Даже с публичным конструктором, так как createClient статический метод, это очень трудно издеваться над ним. Узнайте об инъекции зависимостей, не используйте singleton anti-pattern, добавьте ClientFactory в открытый конструктор, убедитесь, что createClient - это метод экземпляра, а не статический метод. –

+0

Я бы также подумал о том, чтобы не изобретать колесо. Кэш не является потокобезопасным (что может быть или не быть проблемой), и в Guava доступны готовые кэш-кеши, например. –

+0

благодарит за комментарии .... оценил – blu10

ответ

1

Вы можете сделать много вещей, но я думаю, что с точки зрения тестирования Singleton-pattern не является хорошим выбором.

  1. Если вы используете Mockito, вы должны извлечь ClientFactory.createClient() вызов в функции пакета публичного (по умолчанию). Мокито может шпионить за одиночками: spy(MyCache.class), и вы можете изменить поведение извлеченной функции. Таким образом, вы заменили ClientFactory.

  2. Вы можете заменить конструктор private на пакет-public contructor, а также вы должны извлечь функцию, упомянутую в первом решении. После этих изменений вы можете расширить MyCache в тестовом классе (без Mockito).

  3. Вы можете извлечь функциональность MyCache в пакетно-открытый класс, который не является одиночным (но не может звонить извне). Вы можете протестировать его красиво, и MyCache будет только одноэлементной оболочкой выделенного класса.

Я думаю, что отражение является анти-шаблоном, но я знаю, что модификатор доступа по умолчанию (пустая строка) также уродливый.

Несколько слов о вашем singleton-pattern. Это не плохо, если у вас есть только один поток, но если вы находитесь в многопоточной среде, вам нужно это коды:

// you need volatile, because of JVM thread caching 
private static volatile MyCache instance; 

private MyCache() {} 

public static MyCache getInstance() { 
    if (instance == null) { 
     synchronize(MyCache.class) { 
      // yes, you need double check, because of threads 
      if (instance == null) { 
       instance = new MyCache(); 
      } 
     } 
    } 
    return instance; 
} 
+0

Мне нравится звук третьего варианта, но не совсем уверен ... как структура id это ... любой псевдокод, который вы могли бы поделиться – blu10

+0

Ваш файл MyCache будет то же, но конструктор будет общедоступным и не будет иметь функцию getInstance, и будет класс MyCacheWrapper, который функция getDetails вызывает функцию getDetails для своего экземпляра (MyCache), а функция getInstance создает новый MyCache(). Это нормально или я должен написать два файла? –

+0

ОК, я думаю, я понимаю, что я тоже думал или добавлял метод setter к этому классу ... может быть проще ... что вы думаете? – blu10

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