Jak większość ludzi, którzy znaleźli ten wątek, pisałem kilka testów jednostkowych i potrzebowałem zmodyfikować zmienne środowiskowe, aby ustawić odpowiednie warunki do uruchomienia testu. Jednak znalazłem, że najbardziej uprzywilejowane odpowiedzi miały pewne problemy i / lub były bardzo tajemnicze lub zbyt skomplikowane. Mamy nadzieję, że pomoże to innym w szybszym rozwiązaniu problemu.
Po pierwsze, w końcu uznałem rozwiązanie @Hubert Grzeskowiak za najprostsze i zadziałało dla mnie. Chciałbym najpierw do tego dojść. Opiera się na odpowiedzi @Edward Campbell, ale bez komplikacji dla wyszukiwania w pętli.
Zacząłem jednak od rozwiązania @ pushy, które uzyskało najwięcej pozytywnych opinii. Jest to kombinacja @anonymous i @Edward Campbell's. @pushy twierdzi, że oba podejścia są potrzebne, aby objąć zarówno środowisko Linux, jak i Windows. Pracuję pod OS X i stwierdzam, że oba działają (po rozwiązaniu problemu z podejściem @anonymous). Jak zauważyli inni, to rozwiązanie działa przez większość czasu, ale nie wszystkie.
Myślę, że źródłem większości nieporozumień jest rozwiązanie @ anonimowe działające w polu „Środowisko”. Patrząc na definicję struktury ProcessEnvironment , „środowisko” nie jest Mapą <Ciąg, Ciąg>, ale raczej Mapą <Zmienna, Wartość>. Czyszczenie mapy działa poprawnie, ale operacja putAll odbudowuje mapę Map <String, String>, co potencjalnie powoduje problemy, gdy kolejne operacje działają na strukturze danych przy użyciu normalnego interfejsu API, który oczekuje Map <Variable, Value>. Problemem jest także dostęp do / usuwanie poszczególnych elementów. Rozwiązaniem jest dostęp do „Środowiska” pośrednio poprzez „Środowisko modyfikowalne”. Ale ponieważ jest to typ UnmodifiableMapdostępu należy dokonać za pośrednictwem prywatnej zmiennej „m” typu UnmodifiableMap. Zobacz getModifiableEnvironmentMap2 w kodzie poniżej.
W moim przypadku musiałem usunąć niektóre zmienne środowiskowe z mojego testu (inne powinny pozostać niezmienione). Następnie chciałem przywrócić zmienne środowiskowe do ich poprzedniego stanu po teście. Poniższe procedury ułatwiają to. Przetestowałem obie wersje getModifiableEnvironmentMap na OS X i obie działają równorzędnie. Chociaż w oparciu o komentarze w tym wątku, jeden może być lepszym wyborem niż drugi, w zależności od środowiska.
Uwaga: Nie uwzględniłem dostępu do pola „theCaseInsensitiveEnvironmentField”, ponieważ wydaje się, że jest ono specyficzne dla systemu Windows i nie miałem możliwości go przetestować, ale dodanie go powinno być proste.
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);
}