为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
相关产品推荐
相关产品推荐

