Як і більшість людей, які знайшли цю тему, я писав кілька тестових одиниць і мені потрібно було змінити змінні середовища, щоб встановити правильні умови для запуску тесту. Однак я виявив, що найбільш відповідні відповіді мали деякі питання та / або були дуже виразними або надто складними. Сподіваємось, це допоможе іншим швидше розібратися з рішенням.
По-перше, я нарешті знайшов рішення @Hubert Grzeskowiak найпростішим, і воно працювало для мене. Я б хотів, щоб я прийшов до цього першим. Він заснований на відповіді @Edward Кемпбелла, але без ускладнень для пошуку циклу.
Однак я почав з рішення @ pushy, яке отримало найбільше відгуків. Це комбо @anonymous та @Edward Campbell's. @pushy стверджує, що обидва підходи потрібні для покриття обох середовищ Linux та Windows. Я працюю в OS X і виявляю, що обидва працюють (раз виправлена проблема з @anonymous підходом). Як зазначали інші, це рішення працює більшу частину часу, але не всі.
Я думаю, що джерело більшої частини плутанини походить від рішення @ anonymous, яке працює в полі "TheEl Environment". Дивлячись на визначення структури ProcessEnvironment , "довкілля" - це не карта <String, String>, а скоріше це Map <Змінна, Значення>. Очищення карти працює нормально, але операція putAll відновлює карту Map <String, String>, яка потенційно спричиняє проблеми при наступних операціях над структурою даних за допомогою звичайного API, який очікує на карту <Змінна, Значення>. Також проблема / доступ до окремих елементів є проблемою. Рішення полягає в тому, щоб отримати доступ до "довкілля" опосередковано через "незмінне середовище". Але оскільки це тип UnmodifiableMapдоступ повинен здійснюватися через приватну змінну 'm' типу UnmodifiableMap. Дивіться getModifiableEnvironmentMap2 у коді нижче.
У моєму випадку мені потрібно було видалити деякі змінні середовища для мого тесту (інші повинні бути незмінними). Тоді я хотів відновити змінні середовища до їх попереднього стану після тесту. Підпрограми внизу роблять це прямо вперед. Я протестував обидві версії getModifiableEnvironmentMap на OS X, і обидві працюють рівнозначно. Хоча на основі коментарів у цій темі, один може бути кращим вибором, ніж інший, залежно від середовища.
Примітка. Я не включав доступ до "theCaseInsensitiveEnvironmentField", оскільки це, здається, є специфічним для Windows, і я не мав можливості його перевірити, але додавати його слід прямо.
private Map<String, String> getModifiableEnvironmentMap() {
try {
Map<String,String> unmodifiableEnv = System.getenv();
Class<?> cl = unmodifiableEnv.getClass();
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Map<String,String> modifiableEnv = (Map<String,String>) field.get(unmodifiableEnv);
return modifiableEnv;
} catch(Exception e) {
throw new RuntimeException("Unable to access writable environment variable map.");
}
}
private Map<String, String> getModifiableEnvironmentMap2() {
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theUnmodifiableEnvironmentField = processEnvironmentClass.getDeclaredField("theUnmodifiableEnvironment");
theUnmodifiableEnvironmentField.setAccessible(true);
Map<String,String> theUnmodifiableEnvironment = (Map<String,String>)theUnmodifiableEnvironmentField.get(null);
Class<?> theUnmodifiableEnvironmentClass = theUnmodifiableEnvironment.getClass();
Field theModifiableEnvField = theUnmodifiableEnvironmentClass.getDeclaredField("m");
theModifiableEnvField.setAccessible(true);
Map<String,String> modifiableEnv = (Map<String,String>) theModifiableEnvField.get(theUnmodifiableEnvironment);
return modifiableEnv;
} catch(Exception e) {
throw new RuntimeException("Unable to access writable environment variable map.");
}
}
private Map<String, String> clearEnvironmentVars(String[] keys) {
Map<String,String> modifiableEnv = getModifiableEnvironmentMap();
HashMap<String, String> savedVals = new HashMap<String, String>();
for(String k : keys) {
String val = modifiableEnv.remove(k);
if (val != null) { savedVals.put(k, val); }
}
return savedVals;
}
private void setEnvironmentVars(Map<String, String> varMap) {
getModifiableEnvironmentMap().putAll(varMap);
}
@Test
public void myTest() {
String[] keys = { "key1", "key2", "key3" };
Map<String, String> savedVars = clearEnvironmentVars(keys);
// do test
setEnvironmentVars(savedVars);
}