编译器优化会导致使用原始静态最终值,即使它被JMockit更改

时间:2012-12-20 21:03:23

标签: jmockit

请考虑以下使用JSch创建SSH连接的代码:

public class DoSsh {
  private static final int DEFAULT_PORT = 22;

  public DoSsh(String user, String pass) {
    JSch jsch = new JSch();
    Session sess = jsch.getSession(user, pass, DEFAULT_PORT);
    ...

以下使用JMockit的测试代码:

@Test
public void testDoShs() {
  // Change the default port
  Deencapsulation.setField(DoSsh.class, "DEFAULT_PORT", 2222);
  DoSsh ssh = new DoSsh("me","mypass");
  ...

此处的目标是使SSH连接在测试期间使用备用端口(在本例中为2222)以连接到内存中的SSH服务器(Apache MIRA)。

当我调试这个时,我可以看到'DEFAULT_PORT'的值确实已经改变了(谢谢JMockit :-)问题是编译器已经优化了对'jsch.getSession'的调用并对其进行了硬编码其原始值为22。所以当我在调试器中进入该调用时,即使传入的值是2222,调用内的值也是22。

我的问题是,任何人都可以建议一种方法来解决这个问题,而不涉及使DEFAULT_PORT成为非最终版本吗?

1 个答案:

答案 0 :(得分:2)

找到我自己的答案。它涉及模拟对'jsch.getSession'的调用,但随后使用所需的端口号从模拟中调用实际版本。这基本上是一种AOP方法。不使用去封装。这是代码:

@MockClass(realClass = JSch.class)
public static class MockedJSch {
    public JSch it;
    @Mock(reentrant = true)
    public Session getSession(final String user, final String pass, final int port) throws JSchException {
        return it.getSession(user, pass, TESTING_PORT);
    }
}

@BeforeMethod
public void beforeMethod() {
  Mockit.setUpMocks(MockedJSch.class);
}

这里有两点需要注意。

  1. 模拟方法标记为“可重入”。
  2. mock有一个名为“it”的公共实例成员,用于调用“真实”方法。该实例成员在JMockit的内部初始化,以引用调用此方法的实例,并且该引用可以访问该方法的“真实”版本。