如何从Java设置环境变量?我看到我可以使用ProcessBuilder
为子进程执行此操作。不过,我有几个子进程要启动,所以我宁愿修改当前进程的环境,让子进程继承它。
获取单个环境变量有System.getenv(String)
。我还可以使用Map
获取System.getenv()
完整的环境变量集。但是,在put()
上调用Map
会引发UnsupportedOperationException
- 显然它们意味着环境只能被读取。并且,没有System.setenv()
。
那么,有没有办法在当前运行的进程中设置环境变量?如果是这样,怎么样?如果没有,理由是什么? (这是因为这是Java,因此我不应该做一些邪恶的非便携式过时的事情,比如触摸我的环境吗?)如果没有,那么管理环境变量的任何好建议都会改变我需要提供给几个子过程?
答案 0 :(得分:202)
要在需要为单元测试设置特定环境值的场景中使用,您可能会发现以下hack非常有用。它将更改整个JVM中的环境变量(因此请确保在测试后重置所有更改),但不会改变您的系统环境。
我发现爱德华·坎贝尔和匿名的两个脏黑客的组合效果最好,因为其中一个在linux下不起作用,一个在Windows 7下不起作用。所以为了得到一个多平台的邪恶黑客,我把它们结合起来:
protected static void setEnv(Map<String, String> newenv) throws Exception {
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
} catch (NoSuchFieldException e) {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for(Class cl : classes) {
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
}
}
这就像魅力一样。对这些黑客的两位作者的完全信任。
答案 1 :(得分:84)
(是因为这是Java,因此我不应该做一些邪恶的非便携式过时的事情,比如触摸我的环境吗?)
我觉得你已经敲了敲头。
减轻负担的一种可能方法是分解方法
void setUpEnvironment(ProcessBuilder builder) {
Map<String, String> env = builder.environment();
// blah blah
}
并在启动它们之前传递任何ProcessBuilder
。
此外,您可能已经知道这一点,但您可以使用相同的ProcessBuilder
启动多个进程。因此,如果您的子流程相同,则无需反复进行此设置。
答案 2 :(得分:48)
public static void set(Map<String, String> newenv) throws Exception {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for(Class cl : classes) {
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
}
或者根据thejoshwolfe的建议添加/更新单个var并删除循环。
@SuppressWarnings({ "unchecked" })
public static void updateEnv(String name, String val) throws ReflectiveOperationException {
Map<String, String> env = System.getenv();
Field field = env.getClass().getDeclaredField("m");
field.setAccessible(true);
((Map<String, String>) field.get(env)).put(name, val);
}
答案 3 :(得分:17)
// this is a dirty hack - but should be ok for a unittest.
private void setNewEnvironmentHack(Map<String, String> newenv) throws Exception
{
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.clear();
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.clear();
cienv.putAll(newenv);
}
答案 4 :(得分:16)
在Android上,该接口通过Libcore.os作为一种隐藏的API公开。
Libcore.os.setenv("VAR", "value", bOverwrite);
Libcore.os.getenv("VAR"));
Libcore类以及接口操作系统是公共的。只缺少类声明,需要向链接器显示。无需将类添加到应用程序中,但如果包含它也不会受到影响。
package libcore.io;
public final class Libcore {
private Libcore() { }
public static Os os;
}
package libcore.io;
public interface Os {
public String getenv(String name);
public void setenv(String name, String value, boolean overwrite) throws ErrnoException;
}
答案 5 :(得分:10)
设置单个环境变量(基于Edward Campbell的回答):
public static void setEnv(String key, String value) {
try {
Map<String, String> env = System.getenv();
Class<?> cl = env.getClass();
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Map<String, String> writableEnv = (Map<String, String>) field.get(env);
writableEnv.put(key, value);
} catch (Exception e) {
throw new IllegalStateException("Failed to set environment variable", e);
}
}
<强>用法:强>
首先,将该方法放在您想要的任何类中,例如SystemUtil。
SystemUtil.setEnv("SHELL", "/bin/bash");
如果您在此之后致电System.getenv("SHELL")
,您将获得"/bin/bash"
。
答案 6 :(得分:7)
事实证明来自@ pushy / @ anonymous / @ Edward Campbell的解决方案在Android上不起作用,因为Android不是真正的Java。具体来说,Android根本没有java.lang.ProcessEnvironment
。但事实证明在Android中更容易,你只需要对POSIX setenv()
进行JNI调用:
在C / JNI中:
JNIEXPORT jint JNICALL Java_com_example_posixtest_Posix_setenv
(JNIEnv* env, jclass clazz, jstring key, jstring value, jboolean overwrite)
{
char* k = (char *) (*env)->GetStringUTFChars(env, key, NULL);
char* v = (char *) (*env)->GetStringUTFChars(env, value, NULL);
int err = setenv(k, v, overwrite);
(*env)->ReleaseStringUTFChars(env, key, k);
(*env)->ReleaseStringUTFChars(env, value, v);
return err;
}
在Java中:
public class Posix {
public static native int setenv(String key, String value, boolean overwrite);
private void runTest() {
Posix.setenv("LD_LIBRARY_PATH", "foo", true);
}
}
答案 7 :(得分:6)
这是@ paul-blair转换为Java的答案的组合,其中包括保罗布莱尔指出的一些清理以及似乎在@pushy的代码内部的一些错误,这些错误由@Edward Campbell组成匿名。
我不能强调这个代码应该只用于测试多少,而且非常hacky。但是对于需要在测试中设置环境的情况,这正是我所需要的。
这还包括我的一些小修改,允许代码在
上运行的两个Windows上运行java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
以及在
上运行的Centosopenjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)
实施:
/**
* Sets an environment variable FOR THE CURRENT RUN OF THE JVM
* Does not actually modify the system's environment variables,
* but rather only the copy of the variables that java has taken,
* and hence should only be used for testing purposes!
* @param key The Name of the variable to set
* @param value The value of the variable to set
*/
@SuppressWarnings("unchecked")
public static <K,V> void setenv(final String key, final String value) {
try {
/// we obtain the actual environment
final Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
final Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
final boolean environmentAccessibility = theEnvironmentField.isAccessible();
theEnvironmentField.setAccessible(true);
final Map<K,V> env = (Map<K, V>) theEnvironmentField.get(null);
if (SystemUtils.IS_OS_WINDOWS) {
// This is all that is needed on windows running java jdk 1.8.0_92
if (value == null) {
env.remove(key);
} else {
env.put((K) key, (V) value);
}
} else {
// This is triggered to work on openjdk 1.8.0_91
// The ProcessEnvironment$Variable is the key of the map
final Class<K> variableClass = (Class<K>) Class.forName("java.lang.ProcessEnvironment$Variable");
final Method convertToVariable = variableClass.getMethod("valueOf", String.class);
final boolean conversionVariableAccessibility = convertToVariable.isAccessible();
convertToVariable.setAccessible(true);
// The ProcessEnvironment$Value is the value fo the map
final Class<V> valueClass = (Class<V>) Class.forName("java.lang.ProcessEnvironment$Value");
final Method convertToValue = valueClass.getMethod("valueOf", String.class);
final boolean conversionValueAccessibility = convertToValue.isAccessible();
convertToValue.setAccessible(true);
if (value == null) {
env.remove(convertToVariable.invoke(null, key));
} else {
// we place the new value inside the map after conversion so as to
// avoid class cast exceptions when rerunning this code
env.put((K) convertToVariable.invoke(null, key), (V) convertToValue.invoke(null, value));
// reset accessibility to what they were
convertToValue.setAccessible(conversionValueAccessibility);
convertToVariable.setAccessible(conversionVariableAccessibility);
}
}
// reset environment accessibility
theEnvironmentField.setAccessible(environmentAccessibility);
// we apply the same to the case insensitive environment
final Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
final boolean insensitiveAccessibility = theCaseInsensitiveEnvironmentField.isAccessible();
theCaseInsensitiveEnvironmentField.setAccessible(true);
// Not entirely sure if this needs to be casted to ProcessEnvironment$Variable and $Value as well
final Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
if (value == null) {
// remove if null
cienv.remove(key);
} else {
cienv.put(key, value);
}
theCaseInsensitiveEnvironmentField.setAccessible(insensitiveAccessibility);
} catch (final ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">", e);
} catch (final NoSuchFieldException e) {
// we could not find theEnvironment
final Map<String, String> env = System.getenv();
Stream.of(Collections.class.getDeclaredClasses())
// obtain the declared classes of type $UnmodifiableMap
.filter(c1 -> "java.util.Collections$UnmodifiableMap".equals(c1.getName()))
.map(c1 -> {
try {
return c1.getDeclaredField("m");
} catch (final NoSuchFieldException e1) {
throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+"> when locating in-class memory map of environment", e1);
}
})
.forEach(field -> {
try {
final boolean fieldAccessibility = field.isAccessible();
field.setAccessible(true);
// we obtain the environment
final Map<String, String> map = (Map<String, String>) field.get(env);
if (value == null) {
// remove if null
map.remove(key);
} else {
map.put(key, value);
}
// reset accessibility
field.setAccessible(fieldAccessibility);
} catch (final ConcurrentModificationException e1) {
// This may happen if we keep backups of the environment before calling this method
// as the map that we kept as a backup may be picked up inside this block.
// So we simply skip this attempt and continue adjusting the other maps
// To avoid this one should always keep individual keys/value backups not the entire map
LOGGER.info("Attempted to modify source map: "+field.getDeclaringClass()+"#"+field.getName(), e1);
} catch (final IllegalAccessException e1) {
throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">. Unable to access field!", e1);
}
});
}
LOGGER.info("Set environment variable <"+key+"> to <"+value+">. Sanity Check: "+System.getenv(key));
}
答案 8 :(得分:3)
尝试上面的pushy的答案,它在大多数情况下都有效。但是,在某些情况下,我会看到这个例外:
java.lang.String cannot be cast to java.lang.ProcessEnvironment$Variable
当方法被多次调用时,由于ProcessEnvironment.
的某些内部类的实现,如果setEnv(..)
方法被多次调用,当检索到密钥时,就会发生这种情况。从theEnvironment
映射,它们现在是字符串(在setEnv(...)
的第一次调用时被放入字符串中)并且不能转换为映射的泛型类型Variable,
,它是私有的内部类ProcessEnvironment.
固定版本(在Scala中),如下所示。希望将其延伸到Java中并不困难。
def setEnv(newenv: java.util.Map[String, String]): Unit = {
try {
val processEnvironmentClass = JavaClass.forName("java.lang.ProcessEnvironment")
val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
theEnvironmentField.setAccessible(true)
val variableClass = JavaClass.forName("java.lang.ProcessEnvironment$Variable")
val convertToVariable = variableClass.getMethod("valueOf", classOf[java.lang.String])
convertToVariable.setAccessible(true)
val valueClass = JavaClass.forName("java.lang.ProcessEnvironment$Value")
val convertToValue = valueClass.getMethod("valueOf", classOf[java.lang.String])
convertToValue.setAccessible(true)
val sampleVariable = convertToVariable.invoke(null, "")
val sampleValue = convertToValue.invoke(null, "")
val env = theEnvironmentField.get(null).asInstanceOf[java.util.Map[sampleVariable.type, sampleValue.type]]
newenv.foreach { case (k, v) => {
val variable = convertToVariable.invoke(null, k).asInstanceOf[sampleVariable.type]
val value = convertToValue.invoke(null, v).asInstanceOf[sampleValue.type]
env.put(variable, value)
}
}
val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
theCaseInsensitiveEnvironmentField.setAccessible(true)
val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]]
cienv.putAll(newenv);
}
catch {
case e : NoSuchFieldException => {
try {
val classes = classOf[java.util.Collections].getDeclaredClasses
val env = System.getenv()
classes foreach (cl => {
if("java.util.Collections$UnmodifiableMap" == cl.getName) {
val field = cl.getDeclaredField("m")
field.setAccessible(true)
val map = field.get(env).asInstanceOf[java.util.Map[String, String]]
// map.clear() // Not sure why this was in the code. It means we need to set all required environment variables.
map.putAll(newenv)
}
})
} catch {
case e2: Exception => e2.printStackTrace()
}
}
case e1: Exception => e1.printStackTrace()
}
}
答案 9 :(得分:3)
在网上浏览一下,看起来有可能用JNI做到这一点。然后你必须从C调用putenv(),你(大概)必须以适用于Windows和UNIX的方式进行调用。
如果可以做到的一切,对于Java本身而言,支持这一点肯定不会太难,而不是让我穿上直夹克。
在其他地方讲Perl的朋友表示,这是因为环境变量是流程全局的,而Java正在努力为良好的设计提供良好的隔离。
答案 10 :(得分:3)
与大多数找到此线程的人一样,我正在编写一些单元测试,需要修改环境变量以设置运行测试的正确条件。但是,我发现最受欢迎的答案有一些问题和/或非常神秘或过于复杂。希望这有助于其他人更快地解决问题。
首先,我终于发现@Hubert Grzeskowiak的解决方案是最简单的,它对我有用。我希望我能先来到那个。它基于@Edward Campbell的答案,但没有复杂的循环搜索。
然而,我开始使用@ pushy的解决方案,这得到了最多的赞成。它是@anonymous和@Edward Campbell的组合。 @pushy声称需要两种方法来涵盖Linux和Windows环境。我在OS X下运行,发现两者都有效(一旦@anonymous方法的问题得到修复)。正如其他人所指出的那样,这种解决方案大部分时间都有效,但不是全部。
我认为大多数混乱的根源来自@ anonymous在'theEnvironment'领域运行的解决方案。看一下ProcessEnvironment结构的定义,'theEnvironment'不是Map&lt;字符串,字符串&gt;而是它是一个地图&lt;变量,值&gt;。清除地图工作正常,但putAll操作重建地图&lt; String,String&gt;,当后续操作使用期望Map&lt;的普通API对数据结构进行操作时,可能会导致问题。变量,值&gt;。此外,访问/删除单个元素是一个问题。解决方案是通过'theUnmodifiableEnvironment'间接访问'theEnvironment'。但由于这是一个UnmodifiableMap类型,因此必须通过UnmodifiableMap类型的私有变量'm'来完成访问。请参阅下面的代码中的getModifiableEnvironmentMap2。
在我的情况下,我需要为我的测试删除一些环境变量(其他变量应保持不变)。然后我想在测试后将环境变量恢复到先前的状态。下面的例程可以直截了当地做。我在OS X上测试了两个版本的getModifiableEnvironmentMap,两者都是等效的。虽然根据这个帖子中的评论,根据环境的不同,一个可能是比另一个更好的选择。
注意:我没有包含对'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);
}
答案 11 :(得分:1)
我偶然发现了这个线程,因为我有一个类似的要求,即我需要永久设置(或更新)环境变量。
所以我研究了-如何通过命令提示符永久设置环境变量,这非常简单!
setx JAVA_LOC C:/Java/JDK
然后我在代码中实现了相同的功能 这是我使用的(假设-JAVA_LOC是环境变量名称)
String cmdCommand = "setx JAVA_LOC " + "C:/Java/JDK";
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("cmd.exe", "/c", cmdCommand);
processBuilder.start();
ProcessBuilder启动cmd.exe并传递所需的命令。 即使您杀死JVM /重新启动系统,环境变量也会保留,因为它与JVM / Program的生命周期无关。
答案 12 :(得分:0)
这是@pushy邪恶answer =)的Kotlin邪恶版本
@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun setEnv(newenv: Map<String, String>) {
try {
val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
theEnvironmentField.isAccessible = true
val env = theEnvironmentField.get(null) as MutableMap<String, String>
env.putAll(newenv)
val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
theCaseInsensitiveEnvironmentField.isAccessible = true
val cienv = theCaseInsensitiveEnvironmentField.get(null) as MutableMap<String, String>
cienv.putAll(newenv)
} catch (e: NoSuchFieldException) {
val classes = Collections::class.java.getDeclaredClasses()
val env = System.getenv()
for (cl in classes) {
if ("java.util.Collections\$UnmodifiableMap" == cl.getName()) {
val field = cl.getDeclaredField("m")
field.setAccessible(true)
val obj = field.get(env)
val map = obj as MutableMap<String, String>
map.clear()
map.putAll(newenv)
}
}
}
至少在macOS Mojave中可以使用。
答案 13 :(得分:0)
如果使用SpringBoot,则可以在以下属性中添加指定环境变量:
was.app.config.properties.toSystemProperties
答案 14 :(得分:0)
@pushy's变体在Windows上有效。
def set_env(newenv):
from java.lang import Class
process_environment = Class.forName("java.lang.ProcessEnvironment")
environment_field = process_environment.getDeclaredField("theEnvironment")
environment_field.setAccessible(True)
env = environment_field.get(None)
env.putAll(newenv)
invariant_environment_field = process_environment.getDeclaredField("theCaseInsensitiveEnvironment");
invariant_environment_field.setAccessible(True)
invevn = invariant_environment_field.get(None)
invevn.putAll(newenv)
用法:
old_environ = dict(os.environ)
old_environ['EPM_ORACLE_HOME'] = r"E:\Oracle\Middleware\EPMSystem11R1"
set_env(old_environ)
答案 15 :(得分:0)
Tim Ryan的答案对我有用...但是我想要Groovy(例如Spock上下文)和simplissimo:
import java.lang.reflect.Field
def getModifiableEnvironmentMap() {
def unmodifiableEnv = System.getenv()
Class cl = unmodifiableEnv.getClass()
Field field = cl.getDeclaredField("m")
field.accessible = true
field.get(unmodifiableEnv)
}
def clearEnvironmentVars( def keys ) {
def savedVals = [:]
keys.each{ key ->
String val = modifiableEnvironmentMap.remove(key)
// thinking about it, I'm not sure why we need this test for null
// but haven't yet done any experiments
if( val != null ) {
savedVals.put( key, val )
}
}
savedVals
}
def setEnvironmentVars(Map varMap) {
modifiableEnvironmentMap.putAll(varMap)
}
// pretend existing Env Var doesn't exist
def PATHVal1 = System.env.PATH
println "PATH val1 |$PATHVal1|"
String[] keys = ["PATH", "key2", "key3"]
def savedVars = clearEnvironmentVars(keys)
def PATHVal2 = System.env.PATH
println "PATH val2 |$PATHVal2|"
// return to reality
setEnvironmentVars(savedVars)
def PATHVal3 = System.env.PATH
println "PATH val3 |$PATHVal3|"
println "System.env |$System.env|"
// pretend a non-existent Env Var exists
setEnvironmentVars( [ 'key4' : 'key4Val' ])
println "key4 val |$System.env.key4|"
答案 16 :(得分:0)
Kotlin的一个版本,在此算法中,我创建了一个装饰器,该装饰器允许您从环境中设置和获取变量。
([\w][\w ]*)\([A-Z]\)
答案 17 :(得分:0)
有三个库可以在单元测试期间执行此操作。
Stefan Birkner 的系统规则和系统 Lambda - https://www.baeldung.com/java-system-rules-junit 允许您执行以下操作:
public class JUnitTest {
@Rule
public EnvironmentVariables environmentVariables = new EnvironmentVariables();
@Test
public void someTest() {
environmentVariables.set("SOME_VARIABLE", "myValue");
// now System.getenv does what you want
}
}
或对于系统 Lambda:
@Test
void execute_code_with_environment_variables(
) throws Exception {
List<String> values = withEnvironmentVariable("first", "first value")
.and("second", "second value")
.execute(() -> asList(
System.getenv("first"),
System.getenv("second")
));
assertEquals(
asList("first value", "second value"),
values
);
}
上述功能也可通过系统存根作为 JUnit 5 扩展提供:
@ExtendWith(SystemStubsExtension.class)
class SomeTest {
@SystemStub
private EnvironmentVariables;
@Test
void theTest() {
environmentVariables.set("SOME_VARIABLE", "myValue");
// now System.getenv does what you want
}
}
System Stubs 向后兼容 System Lambda 和 System Rules,但支持 JUnit 5。
或者,还有 JUnit Pioneer - https://github.com/junit-pioneer/junit-pioneer,它允许在测试时通过注释设置环境变量。
答案 18 :(得分:-1)
我最近根据爱德华的答案进行了Kotlin的实现:
fun setEnv(newEnv: Map<String, String>) {
val unmodifiableMapClass = Collections.unmodifiableMap<Any, Any>(mapOf()).javaClass
with(unmodifiableMapClass.getDeclaredField("m")) {
isAccessible = true
@Suppress("UNCHECKED_CAST")
get(System.getenv()) as MutableMap<String, String>
}.apply {
clear()
putAll(newEnv)
}
}
答案 19 :(得分:-7)
您可以使用-D:
将参数传递到初始java进程中java -cp <classpath> -Dkey1=value -Dkey2=value ...