Я использую Java OWNER для конфигурации на основе свойств.
Я создал статический метод
public static final ApplicationConfiguration config = ConfigFactory.create(ApplicationConfiguration.class,
System.getProperties(), System.getenv());
и я импортирую класс везде, где мне нужен conf.
Излишне говорить, что модульное тестирование - это PITA. Я не смог найти хороший способ переопределить значения в конфигурации.
Я бы не хотел передавать конфигурацию как зависимость в каждом классе. Это добавляет много многословия и не имеет смысла с точки зрения дизайна. То же самое относится к вызову фабрики конфигурации в каждом классе
ApplicationConfiguration config = ConfigFactory.create(ApplicationConfiguration.class,
System.getProperties(), System.getenv());
Есть ли у вас предложения? есть лучшая практика?




Две вещи:
Вы можете создать класс, который предоставляет свойства, и все пользователи будут его использовать:
public class PropertiesAccessor {
private static MyConfiguration mMyConfig = ConfigFactory.create(MyConfiguration.class);
private PropertiesAccessor()
// No need to allow instantiation of this class
}
/**
* Get properties for this application
*
* @return Properties
*/
public static MyConfiguration getProperties() {
return mMyConfig;
}
// for unit testing
@VisibleForTesting
public static void setProperties(MyConfiguration config) {
mMyConfig = config;
}
}
Теперь везде, где вам нужна собственность, вы можете использовать этот статический метод.
PropertiesAccessor.getProperties()
Обратите внимание, что есть метод для тестирования setProperties (). Есть разные способы использовать этот метод. Вы можете создать тестовый файл свойств, загрузить его, а затем вызвать метод setProperties (). Мне нравится использовать такой служебный метод:
public static void initProperties(String fileName) {
Properties testProperties = new Properties();
File file = new File(fileName);
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
testProperties.load(stream);
} catch (IOException e) {
// Log or whatever you want to do
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// Log or whatever you want to do;
}
MyConfiguration config = ConfigFactory.create(MyConfiguration.class, testProperties);
PropertiesAccessor.setProperties(config);
}
Затем у вас могут быть различные файлы свойств.
Или, если вы просто хотите установить несколько свойств, сделайте следующее:
Properties testProperties = new Properties();
testProperties.setProperty("key1", "data1");
testProperties.setProperty("key2", "data2");
final MyConfiguration myConfig = ConfigFactory.create(MyConfiguration.class, testProperties);
PropertiesAccessor.setProperties(myConfig);
Needless to say, unit testing is a PITA. I couldn't find a good way of override the values in the configuration.
У вас могут быть объекты конфигурации Мутабельный. Нет PITA, когда вы читаете руководство.
Но есть подходы получше.
Когда вы знаете ТВЕРДЫЕ принципы, интерфейсы очень легко тестировать и с ними справляться во время тестирования.
import static org.mockito.Mockito.*;
MyConfig cfg = mock(MyConfig.class); // mock object
when(cfg.myConfigurationThing()).thenReturn("whateverYourObjectNeeds");
ObjectThatYouNeedToTest targetObject =
new ObjectThatYouNeedToTest(cfg); // Dependency Injection
// see: http://wiki.c2.com/?ConstructorInjection
assertEquals("expected result", targetObject.whateverYouNeedToTest());
// then you can also verify interactions:
verify(cfg, times(1)).myConfigurationThing();
В приведенном выше фрагменте показан пример Mockito, но существует множество аналогичных сред тестирования.
Проверьте, что такое Макетные объекты, что такое Внедрение зависимости и Разделение интерфейсов.
I would like to avoid passing the config as a dependency in every class.
Если вашим объектам нужна конфигурация, вы должны передать конфигурацию своим объектам. Так и должно быть. Если он многословный, значит, в дизайне вашего приложения есть что-то, что нужно изменить. Например, вы выбрали синглтон со статическим членом в классе, и это не очень хорошо, особенно для тестирования.
Same applies for calling the config factory in every class
Вызывать фабрику конфигураций в каждом классе - плохая идея. Возможно, вы сможете разделить свой файл конфигурации на множество компонентов для конкретных компонентов. Это один путь (мой путь).
Но если вам нужен один огромный файл конфигурации (что не является моим любимым подходом), ваши интерфейсы конфигурации не обязательно должны соответствовать одной и той же структуре: вы можете иметь несколько интерфейсов конфигурации компонентов, читающих из одного файла: это не лучший вариант, если вы используете горячую перезагрузку, и я, вероятно, мог бы сделать больше для модульного построения объектов конфигурации в дереве вложенных интерфейсов конфигурации. Но эй, я сделал это в свободное время для себя и поделился им бесплатно; если люди делают что-то не так, как я, и нуждаются во мне, чтобы поддержать то, как они работают, возможно, они могли бы поддержать разработку, внося хороший код, или нанять мое время, чтобы улучшить его.
Извините за PITA.
Очевидно, есть способы обойти это, но я искал более элегантный способ.
Привет, Луиджи, спасибо за лекцию. всего пара комментариев. Интерфейсы очень легко тестировать, верно, но я имею дело со статическим методом. Это означает, что мне нужно имитировать каждый доступ к свойству, как вы предложили. И это не идеально во время интеграционного тестирования. Существуют фреймворки, которые хорошо справляются с этим сценарием (например, загрузка Spring).