2015-06-13 3 views
3

Существует класс java, он основан на шаблоне Singleton. как сделать модульный тест для этого класса? следующий мой код:как выполнить единичный тест для шаблона Singleton с использованием jmockit

public class ConfigFromFile implements ConfigStrategy { 
    private String endpoint; 
    private final static String CONFIG_FILE = "/conf/config.properties"; 

    private InputStream getInputStream(String configFilePath) throws FileNotFoundException{ 
    return new FileInputStream(configFilePath); 
    } 

    private void initFromFile() { 
    Properties prop = new Properties(); 
    InputStream input = null; 
    try { 
     input = getInputStream(CONFIG_FILE); 
     prop.load(input); 
     endpoint = prop.getProperty("endpoint"); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } finally { 
     if (input != null) { 
     try { 
      input.close(); 
     } catch (IOException e) { 
     } 
     } 
    } 
    } 

    private ConfigFromFile() { 
    initFromFile(); 
    } 

    private static class ConfigFromFileHolder { 
    private static ConfigFromFile instance = new ConfigFromFile(); 
    } 

    public static ConfigFromFile getInstance() { 
    return ConfigFromFileHolder.instance; 
    } 

    @Override 
    public String getEndpoint() { 
     return endpoint; 
    } 
} 

Мне нужно написать модульный тест для этого класса.

  • единичный тест не может вызвать внешний ресурс, поэтому нам нужно высмеять файл «/conf/config.properties». мы можем использовать jmockit.
  • Этот класс основан на шаблоне Singleton. Мы надеемся, что взаимодействие между этими двумя делами не может быть затронуто.

Ниже мой случай:

  1. Случай 1., это обычный случай, содержимое файла «конечная точка = www.baidu.com»
  2. Вариант 2, это ненормальный случай, мы может издеваться над этим файлом не существует.

как реализовать эти случаи? Благодаря!

+0

@namshubwriter вы пропустили ошибку Singleton в своем редактировании. – Fuhrmanator

+0

@Fuhrmanator Обычно я улучшаю форматирование при редактировании вопросов. – NamshubWriter

ответ

0

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

public class ConfigFromFile implements ConfigStrategy { 
    private static final String CONFIG_FILE = "/conf/config.properties"; 
    private final String configFilePath; 
    private String endpoint; 

    // Visible for testing 
    ConfigStrategy(String configFilePath) { 
    this.configFilePath = configFilePath; 
    } 

    private ConfigStrategy() { 
    this(CONFIG_FILE); 
    } 

    private void initFromFile() { 
    try (InputStream input = new FileInputStream(configFilePath)) { 
     Properties prop = new Properties(); 
     prop.load(input); 
     endpoint = prop.getProperty("endpoint"); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 
    } 

    ... 

} 

Примечание Я переписал initFromFile() для использования примерочных с-ресурсов, которые вы можете сделать, если, если вы используете JDK 7 или выше.

Возможно, вам захочется пересмотреть, должен ли этот класс быть статическим одноэлементным. Это не только усложняет проверку кода, но и не может быть настроено на использование разных файлов в разных средах. Помните, что тест для класса является первым пользователем класса API. Если ваш тест трудно записать, это может указывать на проблемы с вашим API.

Если вам нужно ограничиться одним экземпляром, я предлагаю с использованием рамки инъекции зависимостей как Guice или Spring. Если вы используете Spring, ваш класс может реализовать InitializingBean и загрузить конфигурационный файл после того, как класс построен, но прежде, чем он вводится в другой класс:

public class ConfigFromFile implements ConfigStrategy, InitializingBean { 
    private final String configFilePath; 
    private String endpoint; 

    ConfigStrategy(String configFilePath) { 
    this.configFilePath = configFilePath; 
    } 

    @Override 
    public void afterPropertiesSet() throws IOException { 
    try (InputStream input = new FileInputStream(configFilePath)) { 
     Properties prop = new Properties(); 
     prop.load(input); 
     endpoint = prop.getProperty("endpoint"); 
    } 
    } 

    @Override 
    public String getEndpoint() { 
    return endpoint; 
    } 
} 

Да, это весь код, что вам нужно.

  • не нужно поймать исключение
  • исключение, загрузив файл конфигурации не будет проигнорирована
  • нет необходимости иметь getEndpoint() проверку, если инициализация не удалось

Вы можете сделать something similar с Guice.

Но подождите, если вы используете Spring, и вы готовы перенести значение конечной точки в конфигурацию Spring, тогда это станет еще проще!

public class ConfigFromSpring implements ConfigStrategy { 
    private final String endpoint; 

    ConfigStrategy(String endpoint) { 
    this.endpoint = endpoint; 
    } 

    @Override 
    public String getEndpoint() { 
    return endpoint; 
    } 
} 

Класс прост, он не требует каких-либо модульных испытаний.

Ваш боб XML будет выглядеть следующим образом:

<bean id="config" class="examples.ConfigFromSpring"> 
    <constructor-arg type="String" value="end of the road"/> 
</bean> 

Конечно, в этот момент я бы избавиться от ConfigStrategy и установить конфигурацию на объект, который использует конфигурацию.

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