使静态变量可注入
Make a static variable injectable
我正在构建一个需要调用特定端点的 http API 客户端,如下所示:
public class MyApiClient {
private static final String ENDPOINT ="http://myapi....";
}
这里端点不会改变,所以它是常量。但是,我希望能够覆盖它进行测试,以便我可以针对模拟 http 服务器进行测试。
最好的方法是什么?是否只是让它成为一个实例变量并为其提供一个起始值:
private String endpoint = ="http://myapi....";
public void setEndpoint(String endpoint){
...
}
嗯,当然有很多解决方案,其中一种方法是使用具有默认值的系统属性:
private static final String DEFAULT_ENDPOINT = "http://myapi....";
private static final String ENDPOINT =
System.getProperty("my.endpoint", DEFAULT_ENDPOINT);
这样您就可以获得解决问题的可配置方法。如果在初始化静态常量时需要更大的灵活性,您还可以使用 static initializer:
private static final String ENDPOINT;
static {
// do initialization here but do not throw any exceptions (bad practice)
// you can e.g. read from files etc...
// Then assign your constant...
ENDPOINT =
}
系统属性在命令行上作为 -D
参数传递,例如:
java -Dmy.endpoint=http://...
但在我看来,更好的方法是实际注入值到正在使用的class它:
public class ClassThatIsUsingTheConfig {
private final String endpoint;
public ClassThatIsUsingTheConfig(final String endpoint) {
this.endpoint = endpoint;
}
public void someMethod() {
// use endpoint
}
}
然后,选择要在调用方中使用的端点 class。从测试用例来看,这将非常容易模拟。
public class MyTest {
@Test
public void testMethod() {
ClassThatIsUsingTheConfig var = new ClassThatIsUsingTheConfig(TEST_ENDPOINT);
var.someMethod();
}
}
public class MyProdClass {
public void prodMethod() {
ClassThatIsUsingTheConfig var = new ClassThatIsUsingTheConfig(PROD_ENDPOINT);
var.someMethod();
}
}
您可以阅读有关 dependency injection here 的更多信息。
附带说明一下,如果您使用某种框架来管理依赖关系,例如 Spring Framework or CDI,通常能够以各种方式注入属性和常量(例如,基于哪个环境是目前 运行)。例如,当使用 Spring 框架时,您可以在 属性 文件中声明所有常量并使用注释注入 属性:
@Autowired
public ClassWhoIsUsingTheConfig(@Value("my.endoint") final String endpoint) {
this.endpoint = endpoint;
}
prod 的 属性 文件可能是这样的:
my.endpoint=http://prodserver...
而用于测试的 属性 文件将如下所示:
my.endpoint=http://testserver...
使用依赖注入引擎的方法允许以非常灵活的方式处理外部常量、路径、资源等,并在测试代码时简化您的工作。
我正在构建一个需要调用特定端点的 http API 客户端,如下所示:
public class MyApiClient {
private static final String ENDPOINT ="http://myapi....";
}
这里端点不会改变,所以它是常量。但是,我希望能够覆盖它进行测试,以便我可以针对模拟 http 服务器进行测试。
最好的方法是什么?是否只是让它成为一个实例变量并为其提供一个起始值:
private String endpoint = ="http://myapi....";
public void setEndpoint(String endpoint){
...
}
嗯,当然有很多解决方案,其中一种方法是使用具有默认值的系统属性:
private static final String DEFAULT_ENDPOINT = "http://myapi....";
private static final String ENDPOINT =
System.getProperty("my.endpoint", DEFAULT_ENDPOINT);
这样您就可以获得解决问题的可配置方法。如果在初始化静态常量时需要更大的灵活性,您还可以使用 static initializer:
private static final String ENDPOINT;
static {
// do initialization here but do not throw any exceptions (bad practice)
// you can e.g. read from files etc...
// Then assign your constant...
ENDPOINT =
}
系统属性在命令行上作为 -D
参数传递,例如:
java -Dmy.endpoint=http://...
但在我看来,更好的方法是实际注入值到正在使用的class它:
public class ClassThatIsUsingTheConfig {
private final String endpoint;
public ClassThatIsUsingTheConfig(final String endpoint) {
this.endpoint = endpoint;
}
public void someMethod() {
// use endpoint
}
}
然后,选择要在调用方中使用的端点 class。从测试用例来看,这将非常容易模拟。
public class MyTest {
@Test
public void testMethod() {
ClassThatIsUsingTheConfig var = new ClassThatIsUsingTheConfig(TEST_ENDPOINT);
var.someMethod();
}
}
public class MyProdClass {
public void prodMethod() {
ClassThatIsUsingTheConfig var = new ClassThatIsUsingTheConfig(PROD_ENDPOINT);
var.someMethod();
}
}
您可以阅读有关 dependency injection here 的更多信息。
附带说明一下,如果您使用某种框架来管理依赖关系,例如 Spring Framework or CDI,通常能够以各种方式注入属性和常量(例如,基于哪个环境是目前 运行)。例如,当使用 Spring 框架时,您可以在 属性 文件中声明所有常量并使用注释注入 属性:
@Autowired
public ClassWhoIsUsingTheConfig(@Value("my.endoint") final String endpoint) {
this.endpoint = endpoint;
}
prod 的 属性 文件可能是这样的:
my.endpoint=http://prodserver...
而用于测试的 属性 文件将如下所示:
my.endpoint=http://testserver...
使用依赖注入引擎的方法允许以非常灵活的方式处理外部常量、路径、资源等,并在测试代码时简化您的工作。