首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Spock框架测试SFTP客户端

用Spock框架测试SFTP客户端
EN

Stack Overflow用户
提问于 2022-02-11 14:39:03
回答 1查看 420关注 0票数 1

实际上,我们使用JUnit和伟大的FakeSftpServerRule junit规则来测试我们创建的自定义SFTP客户机。效果很好。

最后,为了支持spock框架,我们希望摆脱junit,因为我们试图迁移到groovy。

你们知道FakeSftpServerRule的等价物吗?或者有什么方法可以将junit规则“转换”成与spock规则相当的规则?

非常感谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-11 19:23:58

同一作者还发布了假SFTP服务器Lambda,它独立于测试框架,而不是您使用的JUnit 4规则。

如果您想继续使用旧工具,Spock 1.3也可以使用JUnit 4规则,而在Spock 2.x中,它也可能与JUnit 4兼容层一起工作。

更新:这里是一个使用SSHJ库从SFTP服务器下载文件的示例程序,因此我们正在测试一个主题:

代码语言:javascript
复制
package de.scrum_master.stackoverflow.q71081881;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.xfer.InMemoryDestFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class SFTPFileDownloader {
  private String host;
  private int port;
  private String user;
  private String password;

  public SFTPFileDownloader(String host, int port, String user, String password) {
    this.host = host;
    this.port = port;
    this.user = user;
    this.password = password;
  }

  protected static class ByteArrayInMemoryDestFile extends InMemoryDestFile {
    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    @Override
    public ByteArrayOutputStream getOutputStream() {
      return outputStream;
    }
  }

  public String getFileContent(String path) throws IOException {
    try (
      SSHClient sshClient = setupSshj();
      SFTPClient sftpClient = sshClient.newSFTPClient()
    )
    {
      ByteArrayInMemoryDestFile inMemoryDestFile = new ByteArrayInMemoryDestFile();
      sftpClient.get(path, inMemoryDestFile);
      return inMemoryDestFile.getOutputStream().toString("UTF-8");
    }
  }

  private SSHClient setupSshj() throws IOException {
    SSHClient client = new SSHClient();
    client.addHostKeyVerifier(new PromiscuousVerifier());
    client.connect(host, port);
    client.authPassword(user, password);
    return client;
  }
}

以下Spock规范以两种方式使用假SFTP服务器Lambda:

  1. 在特性方法"use original server class"中,我们按照作者的意愿使用withSftpServer,即配置它并在单个lambda或Groovy闭包中执行交互。唯一能让它更像spockish的方法是将结果分配给先前定义的变量,并在后面的闭包之外的Spock条件中使用它们。正如伦纳德所说,最终产生的Spock规范代码不是最优的,因为消费者贪婪地立即执行所有交互并再次关闭服务器。
  2. 在feature "use custom server class"中,我们使用了一个定制的CloseableFakeSftpServer,它无耻地使用它的父构造函数、方法和字段。在Groovy类中,我们可以这样做。但是当然,对上游库进行一些扩展和开放,以支持更像spock的方式,首先创建和配置服务器,然后执行交互和验证结果,而不局限于lambda或闭包,这样做会好得多。我甚至创建了helper类@AutoCloseable,并使用@AutoCleanup扩展,以避免在cleanup:块中手动关闭。helper类还使用Groovy的@Delegate FakeSftpServer,以便在自己的接口中公开委托的方法。这是一个解决办法,因为不能简单地扩展原始服务器类,因为甚至Groovy也不能调用私有超级构造函数。

因此,这是用于测试变体2的助手类:

代码语言:javascript
复制
package de.scrum_master.stackoverflow.q71081881

import com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer

class CloseableFakeSftpServer implements AutoCloseable {
  @Delegate
  private FakeSftpServer fakeSftpServer
  private Closeable closeServer

  CloseableFakeSftpServer() {
    fakeSftpServer = new FakeSftpServer(FakeSftpServer.createFileSystem())
    closeServer = fakeSftpServer.start(0)
  }

  @Override
  void close() throws Exception {
    fakeSftpServer.fileSystem.close()
    closeServer.close()
  }
}

在这里,我们终于有了两个可供选择的特性方法的规范(我更喜欢第二个):

代码语言:javascript
复制
package de.scrum_master.stackoverflow.q71081881

import spock.lang.AutoCleanup
import spock.lang.Specification

import static com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer.withSftpServer
import static java.nio.charset.StandardCharsets.UTF_8

class SFTPServerTest extends Specification {
  @AutoCleanup
  def server = new CloseableFakeSftpServer()
  def user = "someone"
  def password = "secret"

  def "use original server class"() {
    given:
    def fileContent = null

    when:
    withSftpServer { server ->
      server.addUser(user, password)
      server.putFile("/directory/file.txt", "content of file", UTF_8)
      // Interact with the subject under test
      def client = new SFTPFileDownloader("localhost", server.port, user, password)
      fileContent = client.getFileContent("/directory/file.txt")
    }

    then:
    fileContent == "content of file"
  }

  def "use custom server class"() {
    given: "a preconfigured fake SFTP server"
    server.addUser(user, password)
    server.putFile("/directory/file.txt", "content of file", UTF_8)

    and: "an SFTP client under test"
    def client = new SFTPFileDownloader("localhost", server.port, user, password)

    expect:
    client.getFileContent("/directory/file.txt") == "content of file"
  }

}

在Groovy web控制台中试一试

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71081881

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档