如何模拟 sftp 会话

How to mock a sftp session

我正在更新一些测试。 Before 获取 sftp 会话。为此,用户名和密码已硬编码在属性文件中。出于安全原因,密码无法签入,必须清空。但是单元测试在

失败
private DefaultSftpSessionFactory sftpClientFactory;
private  SftpSession sftpSession;

 @Before
 public void setup() {
    sftpSession = sftpClientFactory.getSession();
    
}

此步骤失败,提示“需要密码或私钥”。我想要一个模拟会话,这样我就不必提供密码了。

关于 unanswered/able 问题 What's the best mock framework for Java?,Mockito 方法是:

  1. 将所需的库放入您的(测试)class 路径中。 (https://mvnrepository.com/artifact/org.mockito)

  2. 模拟 SftpSession。 (通过注释 private @Mock SftpSession sftpSession; ...加上相应的 initialization/enablement,或(手动)通过 sftpSession = Mockito.mock(SftpSession.class);

    一个。看看,是否需要 SessionFactory(用于测试),如果需要,也可以模拟。

  3. Mock/verify/reset 与模拟对象的任何交互(在您的测试中)。 (如 Mockito.when(sftpSession.foo(x,y,z)).then...Mockito.verify(sftpSession, Mockito.times(n)).foo(x,y,z);

进一步阅读:

我不知道相关测试的目的,但作为模拟的替代方法,我可以建议针对功能齐全的 SFTP 服务器进行测试,就像最初预期的那样。

诀窍是使用 Docker 和一些 Docker-enablement java 库,例如 Testcontainers.

  • 选择一个 SFTP 服务器 Docker 图片(atmoz/sftp 可能值得一试 - 从星数和下载量来看) - 确保它易于配置(在 atmoz/sftp可以使用环境变量配置用户 - 请参阅文档)。
  • 使用 Testcontainers 在您的测试中设置服务器(可以使用 GenericContainer#addEnv). Consult the quick start manuals for Junit 4 and Junit Jupiter 设置容器的环境变量以获得详细信息。

如果您使用的是 JUnit 5 Jupiter(也可能很容易适应 JUnit 4),我写了一篇 article 介绍如何使用 atmoz/sftp Docker 图片与 Testcontainers.

可以在此处找到完整的工作示例

https://overflowed.dev/blog/sftp-testing-junit-testcontainers-atmoz-sftp/

这基本上就是您使用 SFTP 定义 TestContainer 的方式

 private static final GenericContainer sftp = new GenericContainer(
            new ImageFromDockerfile()
                    .withDockerfileFromBuilder(builder ->
                            builder
                                    .from("atmoz/sftp:latest")
                                    .run("mkdir -p /home/" + USER + "/upload; chmod -R 007 /home/" + USER)
                                    .build()))
            //.withFileSystemBind(sftpHomeDirectory.getAbsolutePath(), "/home/" + USER + REMOTE_PATH, BindMode.READ_WRITE) //uncomment to mount host directory - not required / recommended
            .withExposedPorts(PORT)
            .withCommand(USER + ":" + PASSWORD + ":1001:::upload");