测试从同一个 class 调用另一个的静态方法

Test static method that call another from same class

我有一个 class:

namespace Models;

use Contracts\PathContract;

class Path implements PathContract
{
    public static function getStorage(string $type): string
    {
        return storage_path(config('logs.storage_path', 'logs'))
            .DIRECTORY_SEPARATOR
            .$type;
    }
    
    public static function directoryExists(string $type): bool
    {
        var_dump(Path::getStorage($type)); // output: .../logs/vendor/orchestra/testbench-core/laravel/storage/logs/myCustomType
        if (is_dir(self::getStorage($type))) {
            return true;
        }

        return false;
    }
}

我想测试directoryExists静态方法:

public function testDirectoryExists(): void
{
    $path = Mockery::mock(Path::class)->makePartial();
    $path->shouldReceive('getStorage')
        ->once()
        ->andReturn('/var/log');

    var_dump($path::getStorage('blah blah blah')); // output: /var/log

    $this->assertTrue($path::directoryExists('myCustomType'));
}

directoryExists 方法开始,getStorage 方法不是 return 模拟值而是 return 真实值。有什么想法吗?

如何测试从同一个 class 调用另一个静态方法?

不不不。 您必须模拟依赖项,而不是测试代码。 静态函数是糟糕的测试设计。

如果函数不是静态的,您可以使用 Filesystem 并模拟它们。

在这种情况下,最好的方法是 mock 使用 temp 目录。

public function testDirectoryExists(): void
{
    //prepare
    $temp = sys_get_temp_dir();
    $logsPath = 'logs';
    $logsDir = $temp.DIRECTORY_SEPARATOR.$logsPath;
    $type = 'someType';
    mkdir($logsDir);

    //mock
    $this->app->useStoragePath($temp);
    config()->set('logs.storage_path', $logsPath);

    //assert not created
    $this->assertFalse(Path::directoryExists($type));

    //assert created
    mkdir($logsDir.DIRECTORY_SEPARATOR.$type);
    $this->assertTrue(Path::directoryExists($type));
}

已更新

或者,如果你使用Laravel,你可以使用File门面:

public static function directoryExists(string $type): bool
{
    return File::isDirectory(self::getStorage($type));
}
public function testDirectoryExists(): void
{
    $type = 'myType';
    $expectedDir = '/logs/vendor/orchestra/testbench-core/laravel/storage/logs/'.$type;

    $mock = Mockery::mock(\Illuminate\Filesystem\Filesystem::class);
    $mock->shouldReceive('isDirectory')
        ->with($expectedDir)
        ->andReturn(true);

    $this->app->instance(\Illuminate\Filesystem\Filesystem::class, $mock);

    $this->assertTrue(Path::directoryExists($type));
}