使用Spock Framework测试SFTP客户端



我们实际上使用JUnit和伟大的FakeSftpServerRulejunit规则来测试我们制作的自定义SFTP客户端。效果很好。

最后,我们想摆脱junit,转而使用spock框架,因为我们试图迁移到groovy。

你们知道CCD_ 3的等价物吗;开关";将junit规则转换为spock规则?

非常感谢。

同一作者还发布了Fake SFTP Server Lambda,与您使用的JUnit 4规则相比,它独立于测试框架。

如果您想继续使用旧工具,Spock1.3也可以使用JUnit4规则,在Spock2.x中,它也可以与JUnit4兼容层一起使用。


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

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闭包中执行交互。让它更具Spock风格的唯一方法是将结果分配给之前定义的变量,并在以后的闭包之外的Spock条件中使用它们。正如Leonard所说,生成的Spock规范代码是次优的,因为消费者渴望立即执行所有交互并再次关闭服务器。

  2. 在特征方法"use custom server class"中,我们使用了一个自定义CloseableFakeSftpServer,它无耻地利用了其父级的私有构造函数、方法和字段。在Groovy类中,我们可以做到这一点。当然,为了支持一种更像spock的方式来首先创建和配置服务器,然后执行交互和验证结果,而不局限于lambda或闭包,对上游库进行扩展和开放会更好。我甚至创建了助手类@AutoCloseable,并使用Spock@AutoCleanup扩展,以避免在cleanup:块中手动关闭。helper类还使用Groovy的@Delegate FakeSftpServer,以便在自己的接口中公开委托的方法。这是一个无法简单扩展原始服务器类的解决方法,因为即使是Groovy也无法调用私有的超级构造函数。

所以这是测试变体#2的助手类:

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()
}
}

在这里,我们终于有了两种可选特征方法的规范(我更喜欢第二种(:

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控制台中尝试一下。

最新更新