เช่นเดียวกับคนส่วนใหญ่ที่พบเธรดนี้ฉันกำลังเขียนการทดสอบหน่วยและจำเป็นต้องแก้ไขตัวแปรสภาพแวดล้อมเพื่อตั้งค่าเงื่อนไขที่ถูกต้องสำหรับการทดสอบเพื่อให้ทำงานได้ อย่างไรก็ตามฉันพบคำตอบที่ upvoted ที่สุดมีปัญหาบางอย่างและ / หรือมีความลับหรือซับซ้อนเกินไป หวังว่านี่จะช่วยให้ผู้อื่นแก้ไขปัญหาได้เร็วขึ้น
ก่อนอื่นฉันก็พบวิธีแก้ปัญหาของ @Hubert Grzeskowiak ที่ง่ายที่สุดและใช้ได้สำหรับฉัน ฉันหวังว่าฉันจะได้มาที่หนึ่งก่อน มันขึ้นอยู่กับคำตอบของ @Edward Campbell แต่ไม่มีความซับซ้อนในการค้นหาลูป
อย่างไรก็ตามฉันเริ่มต้นด้วยวิธีแก้ปัญหาของ @ pushy ซึ่งมี upvotes มากที่สุด มันเป็นคำสั่งผสมของ @anonymous และ @Edward Campbell's @pushy อ้างว่าจำเป็นต้องใช้ทั้งสองวิธีเพื่อครอบคลุมทั้งสภาพแวดล้อม Linux และ Windows ฉันทำงานภายใต้ OS X และพบว่าทำงานได้ทั้งคู่ (เมื่อปัญหาเกี่ยวกับ @anonymous ได้รับการแก้ไขแล้ว) ดังที่คนอื่น ๆ ได้กล่าวถึงวิธีการแก้ปัญหานี้ใช้เวลาส่วนใหญ่ แต่ไม่ใช่ทั้งหมด
ฉันคิดว่าแหล่งที่มาของความสับสนส่วนใหญ่มาจากวิธีแก้ปัญหาของ @ anonymous ในส่วน 'theEnvironment' ดูที่คำจำกัดความของProcessEnvironmentโครงสร้าง 'theEnvironment' ไม่ใช่ Map <String, String> แต่เป็น Map <Variable, Value> การล้างแผนที่ใช้งานได้ดี แต่การดำเนินการ putAll จะสร้างแผนที่ใหม่เป็น Map <String, String> ซึ่งอาจทำให้เกิดปัญหาเมื่อการดำเนินการตามมาดำเนินการกับโครงสร้างข้อมูลโดยใช้ API ปกติที่คาดว่าแผนที่ <Variable, Value> นอกจากนี้การเข้าถึง / ลบองค์ประกอบแต่ละรายการก็เป็นปัญหาเช่นกัน ทางออกคือการเข้าถึง 'theEnvironment' ทางอ้อมผ่าน 'theUnmodifiableEnvironment' แต่เนื่องจากนี่เป็นประเภท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);
}