【问题标题】:Mocking / Faking static final attribute模拟/伪造静态最终属性
【发布时间】:2018-02-09 17:58:25
【问题描述】:

我有一个班级 RequireJavaVersion,我想为它编写如下所示的测试:

public void execute( EnforcerRuleHelper helper )
     throws EnforcerRuleException
 {
    String javaVersion = SystemUtils.JAVA_VERSION;
    Log log = helper.getLog();

    log.debug( "Detected Java String: '" + javaVersion + "'" );
    javaVersion = normalizeJDKVersion( javaVersion );

此外,我的课程 SystemUtils 看起来像这样:

public static final String JAVA_VERSION = getSystemProperty("java.version");

所以我想写一个这样的测试(使用 JMockit):

@Rule
public ExpectedException exception = ExpectedException.none();

public static class FakeSystemUtils extends MockUp<SystemUtils> {
    private final String fakedVersion;
    public FakeSystemUtils(String version)
    {
        this.fakedVersion = version;
    }
    @Mock
    private final String getSystemProperty(final String property) {
      return this.fakedVersion;
  }    
};
..

new FakeSystemUtils( "1.4" );

rule = new RequireJavaVersion();
rule.setVersion( "1.5" );

exception.expect( EnforcerRuleException.class );
exception.expectMessage( "Detected JDK Version: 1.4 is not in the allowed range 1.5." );
rule.execute( helper );

所以目前的问题是 SystemUtils 类似乎被初始化了一次,之后不再初始化......进一步的测试将失败......(或者我弄错了什么)。

所以我现在不确定我是否走错了方向。 Fake 类只会伪造 getProperty..method 但问题是:这是正确的方法还是我需要进入不同的方向并尝试伪造最终的静态属性?有人有想法或提示吗?

【问题讨论】:

  • 首先没有static final String。有一个带有 getJavaVersion() 方法的类,并传入真实版本或假版本。
  • 重点是编写可测试的代码...... ..
  • 也许我误解了你的建议,但是 SystemUtils 类是通过public static final String JAVA_VERSION=..RequireJavaVersion 使用的,除此之外我不想更改该类?
  • @Antoniossss 我知道,但这无助于解决问题。在我有机会更改代码之前,我会为现有代码编写测试...
  • 我支持“不要为了简单的测试而改变实现”,但其他人可能不同意。如果您不想更改实现,可以使用 PowerMock 的 Whitebox 类将该静态最终字段设置为其他内容。

标签: java unit-testing jmockit


【解决方案1】:

在深入了解@tsolakp 的细节和提示后,我找到了解决方案:

现在我可以为public static final String JAVA_VERSION 设置结果,或多或少简单地检查其余代码。

@RunWith( PowerMockRunner.class )
@PrepareForTest( { SystemUtils.class } )
public class RequireJavaVesionTest
{
   ...
    @Test
    public void first()
        throws EnforcerRuleException
    {
        Whitebox.setInternalState( SystemUtils.class, "JAVA_VERSION", "1.4" );

        rule = new RequireJavaVersion();
        rule.setVersion( "1.5" );

        exception.expect( EnforcerRuleException.class );
        exception.expectMessage( "Detected JDK Version: 1.4 is not in the allowed range 1.5." );
        rule.execute( helper );
    }

这也可以与 JUnit 规则结合使用。

【讨论】:

  • Whitebox.setInternalState 将无法在 Java 的未来版本中使用;在 Java 9 中,我们目前收到“警告:已发生非法反射访问操作”和“警告:所有非法访问操作将在未来版本中被拒绝”。
猜你喜欢
  • 2010-11-27
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 2017-06-07
  • 1970-01-01
相关资源
最近更新 更多