如何使使用全局动态属性的代码可单元测试?
How make code that uses global dynamic properties unit testable?
很多代码需要使用一些全局标志或属性来控制应用程序的流程。许多场景都需要维护动态缓存,动态缓存将有一个标志 lock/unlock 特定的(新)代码。
对于所有这些场景,我通常这样写:
'''
void someMethod(Data data){
if(DynamicProperty.getValue("OK"))
// Do Something
}
DynamicPropery
是一个单例,它会定期从数据库刷新缓存。
这个问题是单元测试有点棘手,到目前为止我已经使用 Jmockit 来解决这个问题 - 它工作正常。
但我想知道是否可以有更好的方法来编写这样的方法,这样可以更容易地进行单元测试。
您可以在某种 PropertyResolverBean
中隔离所有 属性 检索,然后将其注入您的 SUT 并替换静态调用:
private PropertyResolverBean injectedPropertyResolverBean;
void someMethod(Data data){
if(injectedPropertyResolverBean.getValue("OK"))
// Do Something
}
然后您可以使用 Mockito 的基本功能来模拟该 bean 并pre-configure您的测试以您想要的方式进行。
您最终会得到一个遵循 SRP 规则的更可维护、可读和可测试的代码。
一般来说,hard-coded 全局常量应该尽可能避免。由于您需要 mock/switch 一个依赖项,因此将其方法定义为静态很难实现,因为它会将 class 的客户端与前缀为 class 的静态
强烈耦合]
当然,您可能需要在应用程序中维护全局状态,但没有什么能阻止您将其定义为一个对象,您可以将其作为依赖项注入到他们需要的 class 中:
private DynamicProperty dynamicProperty;
public MyClass(DynamicProperty dynamicProperty){
this.dynamicProperty = dynamicProperty;
}
void someMethod(Data data){
if(dynamicProperty.getValue("OK"))
// Do Something
}
这对于依赖注入来说相当直接,但您可以使用普通构造函数或 setter 调用自己完成。
当然,您应该将静态方法更改为实例方法,以允许一种自然的方式来模拟调用。
最简单的方法是提取值 before-hand 并在需要时将其传递给方法。
void someMethod(Data data,SomeProperty dynamicProperty){
if( dynamicProperty whatever)
// Do Something
}
那么您的调用代码将变为:
SomeProperty dynamicProperty = DynamicProperty.getValue("OK");
someMethod(data, dynamicProperty);
这样您就不会真正改变太多,您会在需要时获得动态 属性,因此您无需担心该部分,现在您可以轻松测试您的方法。
这基本上称为函数式编码,您删除了依赖项并仅将数据传递给一个方法,这意味着该方法现在没有依赖项,并且可以通过注入您想要的任何值来轻松测试。
如果你有更多这样的值,我会创建一个单独的 class 并将它们全部集中在一个地方,从中创建一个接口,将其传递给 class 构造函数然后以这种方式使用它。不过,我可能不会只为一个值这样做,除非它真的简化了您的代码。
很多代码需要使用一些全局标志或属性来控制应用程序的流程。许多场景都需要维护动态缓存,动态缓存将有一个标志 lock/unlock 特定的(新)代码。
对于所有这些场景,我通常这样写:
'''
void someMethod(Data data){
if(DynamicProperty.getValue("OK"))
// Do Something
}
DynamicPropery
是一个单例,它会定期从数据库刷新缓存。
这个问题是单元测试有点棘手,到目前为止我已经使用 Jmockit 来解决这个问题 - 它工作正常。
但我想知道是否可以有更好的方法来编写这样的方法,这样可以更容易地进行单元测试。
您可以在某种 PropertyResolverBean
中隔离所有 属性 检索,然后将其注入您的 SUT 并替换静态调用:
private PropertyResolverBean injectedPropertyResolverBean;
void someMethod(Data data){
if(injectedPropertyResolverBean.getValue("OK"))
// Do Something
}
然后您可以使用 Mockito 的基本功能来模拟该 bean 并pre-configure您的测试以您想要的方式进行。
您最终会得到一个遵循 SRP 规则的更可维护、可读和可测试的代码。
一般来说,hard-coded 全局常量应该尽可能避免。由于您需要 mock/switch 一个依赖项,因此将其方法定义为静态很难实现,因为它会将 class 的客户端与前缀为 class 的静态
强烈耦合]
当然,您可能需要在应用程序中维护全局状态,但没有什么能阻止您将其定义为一个对象,您可以将其作为依赖项注入到他们需要的 class 中:
private DynamicProperty dynamicProperty;
public MyClass(DynamicProperty dynamicProperty){
this.dynamicProperty = dynamicProperty;
}
void someMethod(Data data){
if(dynamicProperty.getValue("OK"))
// Do Something
}
这对于依赖注入来说相当直接,但您可以使用普通构造函数或 setter 调用自己完成。
当然,您应该将静态方法更改为实例方法,以允许一种自然的方式来模拟调用。
最简单的方法是提取值 before-hand 并在需要时将其传递给方法。
void someMethod(Data data,SomeProperty dynamicProperty){
if( dynamicProperty whatever)
// Do Something
}
那么您的调用代码将变为:
SomeProperty dynamicProperty = DynamicProperty.getValue("OK");
someMethod(data, dynamicProperty);
这样您就不会真正改变太多,您会在需要时获得动态 属性,因此您无需担心该部分,现在您可以轻松测试您的方法。
这基本上称为函数式编码,您删除了依赖项并仅将数据传递给一个方法,这意味着该方法现在没有依赖项,并且可以通过注入您想要的任何值来轻松测试。
如果你有更多这样的值,我会创建一个单独的 class 并将它们全部集中在一个地方,从中创建一个接口,将其传递给 class 构造函数然后以这种方式使用它。不过,我可能不会只为一个值这样做,除非它真的简化了您的代码。