如何模拟静态成员变量

pkr*_*ish 11 junit unit-testing mocking mockito

我有一个类ClassToTest,它依赖于ClassToMock.

public class ClassToMock {

  private static final String MEMBER_1 = FileReader.readMemeber1();

  protected void someMethod() {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

ClassToTest的单元测试用例.

public class ClassToTestTest {
  private ClassToMock _mock;

  @Before
  public void setUp() throws Exception {
     _mock = mock(ClassToMock.class)
  }

}
Run Code Online (Sandbox Code Playgroud)

在setUp()方法中调用mock时,FileReader.readMemeber1(); 被执行.有办法避免这种情况吗?我认为一种方法是在方法中初始化MEMBER_1.还有其他选择吗?

谢谢!

Ran*_*Lin 11

ClassToMock紧紧地联系在一起FileReader,这就是为什么你无法测试/嘲笑它.而不是使用工具来破解字节代码,以便你可以模拟它.我建议你做一些简单的重构来打破依赖.

步骤1.封装全局引用

迈克尔·费瑟斯(Michael Feathers)出色的着作"有效地使用遗留代码"(Legacy Code)中也引入了这种技术.

标题几乎是自我解释.您可以将其封装在方法中,而不是直接引用全局变量.

在您的情况下,ClassToMock可以重构为:

public class ClassToMock {
  private static final String MEMBER_1 = FileReader.readMemeber1();

  public String getMemberOne() {
    return MEMBER_1;      
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以轻松地使用Mockito进行模拟getMemberOne().

更新旧步骤1不能保证Mockito模拟安全,如果FileReader.readMemeber1()抛出异常,则测试将失败.所以我建议添加另一个步骤来解决它.

步骤1.5.添加Setter和Lazy Getter

由于问题FileReader.readMember1()将在ClassToMock加载后立即调用.我们要推迟它.所以我们FileReader.readMember1()懒洋洋地拨打getter ,打开一个setter.

public class ClassToMock {
  private static String MEMBER_1 = null;

  protected String getMemberOne() {
    if (MEMBER_1 == null) {
      MEMBER_1 = FileReader.readMemeber1();
    }
    return MEMBER_1;      
  }

  public void setMemberOne(String memberOne) {
    MEMBER_1 = memberOne;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,ClassToMock即使没有,你也应该做假Mockito.但是,这不应该是代码的最终状态,一旦准备好测试,就应该继续执行第2步.

步骤2.依赖注射

一旦准备好测试,就应该进一步重构.现在不是MEMBER_1自己阅读.这门课应该MEMBER_1从外面接受.您可以使用setter或构造函数来接收它.下面是使用setter的代码.

public class ClassToMock {
  private String memberOne;
  public void setMemberOne(String memberOne) {
    this.memberOne = memberOne;
  }

  public String getMemberOne() {
    return memberOne;
  }
}
Run Code Online (Sandbox Code Playgroud)

这两步重构非常简单,即使没有手头测试也可以做到.如果代码不那么复杂,您可以执行第2步.然后您可以轻松地进行测试ClassToTest


更新12月8日:回答评论

在这个问题中看到我的另一个答案.