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

如何在PHPUnit中断言两个目录完全相同?如何排查目录文件差异?

嘿,刚好我对这两个场景都很熟悉,给你详细说说~

一、找出两个目录的文件差异(缺失/多余)

最直接的方式是用系统自带的diff命令,它能帮你快速定位目录里的差异:

  • 基础递归对比:在Linux/macOS终端(Windows可以用Git Bash或者WSL)执行下面的命令,-r表示递归遍历子目录,-q只输出差异的文件/目录,不显示内容区别:
    diff -rq dir1/ dir2/
    
    输出结果会像这样,清晰告诉你哪个目录有缺失或多余的文件:

    Only in dir1/: missing_report.pdf
    Only in dir2/: extra_config.ini
    Files dir1/readme.md and dir2/readme.md differ

  • 树形结构对比:如果想更直观看到目录层级的差异,可以先导出两个目录的树形结构再对比:
    tree dir1/ > dir1_tree.txt
    tree dir2/ > dir2_tree.txt
    diff dir1_tree.txt dir2_tree.txt
    
    这样能一目了然看到整个目录结构的不同之处。
二、PHPUnit中断言两个目录完全相同的方法

PHPUnit没有内置的目录断言方法,但我们可以自己封装逻辑,或者借助常用组件来实现,这里给你两种实用方案:

方案1:手动递归对比(轻量无依赖)

自己写一个辅助函数,先对比文件列表,再逐个校验文件内容:

use PHPUnit\Framework\TestCase;

class DirectoryEqualsTest extends TestCase
{
    public function testTwoDirectoriesAreIdentical()
    {
        $targetDir = __DIR__ . '/expected';
        $actualDir = __DIR__ . '/actual';

        // 第一步:校验文件/子目录列表完全一致
        $this->assertEquals(
            $this->getSortedRelativeFileList($targetDir),
            $this->getSortedRelativeFileList($actualDir),
            '目录的文件或子目录存在缺失/多余'
        );

        // 第二步:校验每个文件的内容完全一致
        foreach ($this->getSortedRelativeFileList($targetDir) as $relativePath) {
            $targetFile = $targetDir . '/' . $relativePath;
            $actualFile = $actualDir . '/' . $relativePath;

            // 跳过子目录,只校验文件内容
            if (is_file($targetFile)) {
                $this->assertEquals(
                    file_get_contents($targetFile),
                    file_get_contents($actualFile),
                    "文件内容不匹配:{$relativePath}"
                );
            }
        }
    }

    /**
     * 递归获取目录下所有文件/子目录的相对路径,排序后返回
     */
    private function getSortedRelativeFileList(string $directory): array
    {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::SELF_FIRST
        );

        $filePaths = [];
        foreach ($iterator as $item) {
            // 计算相对于目标目录的路径
            $relativePath = str_replace(rtrim($directory, '/') . '/', '', $item->getPathname());
            $filePaths[] = $relativePath;
        }

        // 排序保证对比顺序一致
        sort($filePaths);
        return $filePaths;
    }
}

方案2:借助Symfony Filesystem组件(更健壮)

如果你的项目已经在用Symfony的Filesystem组件,可以用哈希校验的方式,比直接读内容更高效:

use Symfony\Component\Filesystem\Filesystem;
use PHPUnit\Framework\TestCase;

class DirectoryComparisonTest extends TestCase
{
    public function testDirectoriesMatchExactly()
    {
        $expectedDir = __DIR__ . '/expected';
        $actualDir = __DIR__ . '/actual';
        $filesystem = new Filesystem();

        // 先确保两个目录都存在
        $this->assertDirectoryExists($expectedDir);
        $this->assertDirectoryExists($actualDir);

        // 获取两个目录的所有文件相对路径
        $expectedFiles = $this->getAllRelativeFiles($expectedDir);
        $actualFiles = $this->getAllRelativeFiles($actualDir);

        $this->assertEquals($expectedFiles, $actualFiles, '文件列表不匹配');

        // 用SHA256哈希校验文件内容
        foreach ($expectedFiles as $file) {
            $expectedHash = hash_file('sha256', $expectedDir . '/' . $file);
            $actualHash = hash_file('sha256', $actualDir . '/' . $file);
            $this->assertEquals($expectedHash, $actualHash, "文件 {$file} 内容不一致");
        }
    }

    private function getAllRelativeFiles(string $directory): array
    {
        $files = [];
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS)
        );

        foreach ($iterator as $file) {
            $files[] = $iterator->getSubPathName();
        }

        sort($files);
        return $files;
    }
}

如果不想自己写代码,也可以找一些PHPUnit的第三方扩展(比如phpunit-assertions),不过自己封装的逻辑更轻量,也更容易定制。

内容的提问来源于stack exchange,提问作者Tomas Votruba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:46:32