如何使使用全局动态属性的代码可单元测试?

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 构造函数然后以这种方式使用它。不过,我可能不会只为一个值这样做,除非它真的简化了您的代码。