php - 如何模拟非确定性方法?

标签 php unit-testing mocking mockery

考虑使用非确定性方法的类:

class Foo
{
    public function getSome(): int
    {
        static $int = 0;
        return ++$int;
    }
}

如何使用 Mockery 来模拟相同的行为?

class Bar
{
    public function useFoo(Foo $foo)
    {
        echo $foo->getSome() . ", ";
        echo $foo->getSome() . ", ";
        echo $foo->getSome();
    }
}

$mock = Mockery::mock(Foo::class);
$mock->shouldReceive('getSome')->andReturn(1);
$mock->shouldReceive('getSome')->andReturn(2);
$mock->shouldReceive('getSome')->andReturn(3);

// Should display 1, 2, 3
$bar = new Bar();
$bar->useFoo($mock);

另一个例子:

class Clock
{
    public function getTime(): int
    {
        return time();
    }
}

class Sleeper 
{
    public function sleep(int $seconds): void
    {
        sleep($seconds);
    }
}

如何使用 Mockery 来模拟相同的行为?

class Stoper
{
    private Clock $clock;
    private Sleeper $sleeper;

    public function __construct(Clock $clock, Sleeper $sleeper)
    {
        $this->clock = $clock;
        $this->sleeper = $sleeper;
    }

    public function measure(int $seconds): int
    {
        $start = $this->clock->getTime();
        $this->sleeper->sleep($seconds);

        return $this->clock->getTime();
    }
}

$clockMock = Mockery::mock(Clock::class);
$clockMock->shouldReceive('getTime')->andReturn(1000000001);
$clockMock->shouldReceive('getTime')->andReturn(1000000011);

$sleeperMock = Mockery::mock(Sleeper::class);
$sleeperMock->shouldReceive('sleep');

$stoper = new Stoper($clockMock, $sleeperMock);
$this->assertEquals(10, $stoper->measure(10));

脏溶液

我发现我可以玩肮脏的把戏

class ClockCaller
{
    public function getTime(int $callNumber)
    {
        return (new Clock())->getTime();
    }
}

class Stoper
{
    private ClockCaller $clockCaller;
    private Sleeper $sleeper;

    public function __construct(ClockCaller $clockCaller, Sleeper $sleeper)
    {
        $this->clockCaller = $clockCaller;
        $this->sleeper = $sleeper;
    }

    public function measure(int $seconds): int
    {
        $start = $this->clockCaller->getTime(1);
        $this->sleeper->sleep($seconds);

        return $this->clockCaller->getTime(2);
    }
}

$clockMock = Mockery::mock(ClockCaller::class);
$clockMock->shouldReceive('getTime')->withArgs([1])->andReturn(1000000001);
$clockMock->shouldReceive('getTime')->withArgs([2])->andReturn(1000000011);

但是看起来很恶心

最佳答案

您的问题的答案由Simple Example给出。在 Mockery 文档中。应该连续返回 10、12 和 14 度的温度服务可以这样模拟:

$service = Mockery::mock('service');
$service->shouldReceive('readTemp')
         ->times(3)
         ->andReturn(10, 12, 14);

因此,对于您的 Foo 类:

$mock = Mockery::mock(Foo::class);
$mock->shouldReceive('getSome')
     ->times(3)
     ->andReturn(1, 2, 3);

以及您的时钟:

$clockMock = Mockery::mock(Clock::class);
$clockMock->shouldReceive('getTime')
          ->times(2)
          ->andReturn(1000000001, 1000000011);

关于php - 如何模拟非确定性方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71157233/

相关文章:

php - 安装 FFMPEG 以从虚拟主机上的视频文件生成缩略图

php - 在 setcookie() 之后立即访问 $_COOKIE

reactjs - React - Jest Mock 内部组件

c# - 测试类中的对象实例化

c# - 如何在 ASP.NET Core 中测试 https 重定向?

c - 如何在没有继承的情况下模拟对象(在 C 中)?

PHPUnit:如何测试方法的调用顺序不正确?

php - 如何将 Google Charts 与 mySQL 数据结合使用?

php - 使用 PHP 将文件夹重命名为子文件夹

javascript - 返回数组中的特定对象值