You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为SFTP文件合并功能编写JUnit测试时遇用户ID获取异常的解决方法

解决Apache Commons VFS连接测试SFTP服务器的UID异常及正确编写JUnit测试用例

问题根源

你遇到的异常是因为测试用的Apache Mina SSHD服务器未配置用户UID/GID信息,而Apache Commons VFS建立SFTP连接时会尝试获取当前用户ID,未配置时触发该错误。同时测试SFTP服务器缺少文件系统配置,无法正常创建目录和文件。

正确测试用例编写步骤

1. 完善SFTP测试服务器配置

在setUpSftpServer方法中添加用户认证、UID/GID配置及文件系统根目录(推荐用临时目录避免污染系统):

import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.password.AcceptAllPasswordAuthenticator;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
import org.apache.sshd.server.filesystem.NativeFileSystemFactory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

@BeforeAll
static void setUpSftpServer() throws IOException {
    sshd = SshServer.setUpDefaultServer();
    sshd.setPort(1234);
    sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Path.of("hostkey.ser")));
    
    // 配置密码认证(测试环境简化用全接受)
    sshd.setPasswordAuthenticator(AcceptAllPasswordAuthenticator.INSTANCE);
    // 配置临时文件系统根目录,避免影响本地文件
    Path tempRoot = Files.createTempDirectory("sftp-test-root");
    NativeFileSystemFactory fileSystemFactory = new NativeFileSystemFactory();
    fileSystemFactory.setRootDir(tempRoot.toAbsolutePath().toString());
    sshd.setFileSystemFactory(fileSystemFactory);
    
    sshd.setSubsystemFactories(List.of(new SftpSubsystemFactory()));
    sshd.start();
}

2. 修正VFS连接配置

在getFileObject中简化配置,使用密码认证替代无效的公钥路径,同时创建测试所需的目录和文件:

static FileObject getFileObject() throws URISyntaxException, FileSystemException {
    String user = "uname";
    String password = "pwd";
    String host = "127.0.0.1";
    int port = 1234;
    
    SftpFileSystemConfigBuilder sftpConfigBuilder = SftpFileSystemConfigBuilder.getInstance();
    FileSystemOptions options = new FileSystemOptions();
    
    // 设置密码认证
    sftpConfigBuilder.setPassword(options, password);
    // 测试环境禁用严格主机密钥检查
    sftpConfigBuilder.setStrictHostKeyChecking(options, "no");
    
    // 构建SFTP连接URI
    String uriStr = String.format("sftp://%s:%s@%s:%d/", user, password, host, port);
    FileObject fileObject = VFS.getManager().resolveFile(uriStr, options);
    
    // 创建输入输出目录
    FileObject inputDir = fileObject.resolveFile("/input");
    if (!inputDir.exists()) inputDir.createFolder();
    FileObject outputDir = fileObject.resolveFile("/output");
    if (!outputDir.exists()) outputDir.createFolder();
    
    // 创建测试文件并写入内容
    FileObject testFile = inputDir.resolveFile("a.txt");
    try (OutputStream os = testFile.getContent().getOutputStream(false)) {
        os.write("abc".getBytes(StandardCharsets.UTF_8));
    }
    
    return fileObject;
}

3. 修正测试方法中的错误

修复getContentContent()的笔误,改用正确的getContent(),并完善断言逻辑:

@Test
void exportFileTest() throws IOException, URISyntaxException {
    FileObject fileObject = getFileObject();
    when(sftpConfiguration.connect()).thenReturn(fileObject);
    
    myobject.exportFile(Arrays.asList("a.txt"));
    
    // 获取输入文件内容
    String actualContent = fileObject.resolveFile("/input/a.txt")
            .getContent().getString("UTF-8");
    // 获取输出文件内容
    String expectedContent = fileObject.resolveFile("/output/exportfile.txt")
            .getContent().getString("UTF-8");
    
    assertEquals(actualContent, expectedContent);
}

4. 修复业务代码的潜在问题

调整输出流的作用域,避免循环中重复打开关闭输出流:

public void exportFile(List<String> fileNamesList) throws FileSystemException {
    try (FileObject root = getsFileObject();
         OutputStream outputStream = root.resolveFile("/output/exportfile.txt")
                 .getContent().getOutputStream(true)) {
        for (String file : fileNamesList) {
            FileObject inputFile = root.resolveFile("/input/" + file);
            try (InputStream inputStream = inputFile.getContent().getInputStream()) {
                inputStream.transferTo(outputStream);
            }
        }
    } catch (IOException e) {
        throw new RuntimeException("合并文件失败", e);
    }
}

5. 清理测试资源

添加@AfterAll方法停止SFTP服务器,释放资源:

@AfterAll
static void tearDownSftpServer() throws IOException {
    if (sshd != null && sshd.isStarted()) {
        sshd.stop();
    }
}

内容的提问来源于stack exchange,提问作者Noob of All Arts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:25:30