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

如何创建无实际文件的std::filesystem::directory_entry用于测试?

解决std::filesystem directory_entry模拟的性能兼容问题

你遇到的核心问题是std::filesystem::directory_entry绑定真实文件系统状态,无法直接自定义属性,同时抽象封装会导致生产代码性能大幅下降。以下是两种兼顾性能和测试需求的解决方案:

方案1:C++20原生支持(最优解)

C++20为directory_entry新增了构造函数,允许直接传入自定义file_status,无需依赖真实文件:

// 构造自定义文件状态
fs::file_status regular_status;
regular_status.type(fs::file_type::regular);
regular_status.permissions(fs::perms::owner_read | fs::perms::owner_write);

// 直接创建带自定义状态的directory_entry
fs::directory_entry mock_entry("fake/path/file.txt", regular_status);

对于file_size这类需要文件系统查询的属性,若生产代码中是通过directory_entry::file_size()直接获取,可在测试中结合gmock的动作,将属性获取逻辑也抽象为provider的一部分(仅测试时替换,生产代码仍调用原生方法):

// 扩展directory_provider,添加属性获取接口
class directory_provider {
public:
    virtual std::vector<fs::directory_entry> list_dir(const fs::path& path) = 0;
    virtual uintmax_t file_size(const fs::directory_entry& entry) = 0;
};

// 生产实现直接调用原生方法
class filesystem_provider : public directory_provider {
public:
    // ... 原有list_dir实现
    uintmax_t file_size(const fs::directory_entry& entry) override {
        return entry.file_size();
    }
};

// Mock实现返回自定义大小
class mock_provider : public directory_provider {
public:
    MOCK_METHOD(std::vector<fs::directory_entry>, list_dir, (const fs::path& path), (override));
    MOCK_METHOD(uintmax_t, file_size, (const fs::directory_entry& entry), (override));
};

// 测试时设置预期
TEST(YourTest, MockFileSize) {
    mock_provider mock;
    fs::directory_entry mock_entry("fake/path", fs::file_status{fs::file_type::regular});
    
    ON_CALL(mock, list_dir(testing::_)).WillByDefault(testing::Return({mock_entry}));
    ON_CALL(mock, file_size(testing::_)).WillByDefault(testing::Return(1024));
    
    // 执行测试逻辑
}

这种方式生产代码仅增加了一层极薄的封装,性能损耗可忽略,同时测试完全脱离真实文件系统。

方案2:C++17兼容的临时文件模拟(无代码侵入)

如果项目仍使用C++17,可在测试中创建真实临时文件,构造符合要求的directory_entry后再清理:

TEST(YourTest, MockDirectoryListing) {
    mock_provider mock;

    // 创建临时目录和测试文件
    auto temp_dir = fs::temp_directory_path() / fs::unique_path();
    fs::create_directory(temp_dir);
    auto test_file = temp_dir / "test.bin";
    
    // 设置文件大小为2048字节
    std::ofstream(test_file).seekp(2047).put('\0');

    // 构造真实的directory_entry
    fs::directory_entry file_entry(test_file);
    fs::directory_entry dir_entry(temp_dir);

    // 设置mock返回值
    ON_CALL(mock, list_dir(testing::_))
        .WillByDefault(testing::Return(std::vector<fs::directory_entry>{file_entry, dir_entry}));

    // 执行测试逻辑...

    // 清理临时文件
    fs::remove_all(temp_dir);
}

该方案生产代码零改动,完全保留原生性能,仅测试阶段有少量IO开销,适合对性能敏感的场景。

为什么抽象封装会导致性能下降?

你提到的directory_entry_pod或多态指针方案,本质是引入了额外的内存拷贝或虚函数调用。在遍历大型仓库(如Linux内核)时,这些开销会被海量文件操作放大,最终导致50%的性能损耗。因此,优先选择不修改生产代码结构的模拟方案。

内容的提问来源于stack exchange,提问作者Dominik Kaszewski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 16:21:01