2

考虑以下使用 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 非最终的解决方法吗?

4

1 回答 1

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. 模拟有一个名为“it”的公共实例成员,用于调用“真实”方法。该实例成员在 JMockit 内部的某处被初始化,以引用调用此方法的实例,并且该引用可以访问该方法的“真实”版本。
于 2012-12-20T22:57:59.947 回答