PHPUnit模拟返回值和使用特定参数调用的不同方法相同类的次数

时间:2017-08-03 22:02:17

标签: php unit-testing phpunit

我的情景类似于以下内容:

class ToMock
{
    public function iReturn()
    {
        return time();
    }

    public function callMe1($arg1, $arg2)
    {
        return true;
    }

    public function callMe2($arg1, $arg2)
    {
        return true;
    }
}

class ToTest
{
    public function feedMe(ToMock $toMock)
    {
        if ($toMock->iReturn() > 100) {
            $toMock->callMe1(5, 10);
        }

        if ($toMock->iReturn() < 200) {
            $toMock->callMe2(15, 20);
        }
    }
}

现在,我想测试ToMock::iReturn()是否会返回150,ToTest::feedMe()调用ToMock::callMe1()一次使用5和10,ToMock::callMe2()一次使用15和20。

我知道我可以模拟ToMock::iReturn返回150,我也可以通过提供的参数来模拟ToMock以期望一个特定的方法。但是,是否有可能在同一时间完成所有这些工作?如果是的话,它会是什么样子?

2 个答案:

答案 0 :(得分:1)

如果我理解你的问题,那么测试代码可能看起来像

class MockingExpectationsTest extends PHPUnit_Framework_TestCase
{
    private $obj;
    private $mock;

    public function setUp(){
        $this->mock = $this->createMock(ToMock::class);
        $this->obj = new ToTest();
    }

    public function testExpectations(){
        $this->mock->expects($this->exactly(2))
                   ->method('iReturn')
                   ->willReturn(150);
        $this->mock->expects($this->exactly(1))
                   ->method('callMe1')
                    ->with(5, 10);
        $this->mock->expects($this->exactly(1))
                   ->method('callMe2')
                    ->with(15, 20);
        $this->obj->feedMe($this->mock);
    }
}

答案 1 :(得分:1)

是的,是的。

以下是涵盖ToTest的测试示例:

<?php

use PHPUnit\Framework\TestCase;

class ToTestTest extends TestCase
{
    /**
     * @dataProvider providerTimeBetween0And100
     *
     * @param int $time
     */
    public function testFeedMeWhenTimeIsBetween0And100($time)
    {
        $toMock = $this->createMock(ToMock::class);

        $toMock
            ->expects($this->exactly(2))
            ->method('iReturn')
            ->willReturn($time);

        $toMock
            ->expects($this->never())
            ->method('callMe1');

        $toMock
            ->expects($this->once())
            ->method('callMe2')
            ->with(
                $this->identicalTo(15),
                $this->identicalTo(20)
            );

        $toTest = new ToTest();

        $toTest->feedMe($toMock);
    }

    public function providerTimeBetween0And100()
    {
        return $this->providerTimeBetween(0, 100);
    }

    /**
     * @dataProvider providerTimeBetween101And199
     *
     * @param int $time
     */
    public function testFeedMeWhenTimeIsBetween101And199($time)
    {
        $toMock = $this->createMock(ToMock::class);

        $toMock
            ->expects($this->exactly(2))
            ->method('iReturn')
            ->willReturn($time);

        $toMock
            ->expects($this->once())
            ->method('callMe1')
            ->with(
                $this->identicalTo(5),
                $this->identicalTo(10)
            );

        $toMock
            ->expects($this->once())
            ->method('callMe2')
            ->with(
                $this->identicalTo(15),
                $this->identicalTo(20)
            );

        $toTest = new ToTest();

        $toTest->feedMe($toMock);
    }

    public function providerTimeBetween101And199()
    {
        return $this->providerTimeBetween(101, 199);
    }
    /**
     * @dataProvider providerTimeGreaterThan199
     *
     * @param int $time
     */
    public function testFeedMeWhenTimeIsGreaterThan199($time)
    {
        $toMock = $this->createMock(ToMock::class);

        $toMock
            ->expects($this->exactly(2))
            ->method('iReturn')
            ->willReturn($time);

        $toMock
            ->expects($this->once())
            ->method('callMe1')
            ->with(
                $this->identicalTo(5),
                $this->identicalTo(10)
            );

        $toMock
            ->expects($this->never())
            ->method('callMe2');

        $toTest = new ToTest();

        $toTest->feedMe($toMock);
    }

    public function providerTimeGreaterThan199()
    {
        return $this->providerTimeBetween(200, 300);
    }

    private function providerTimeBetween($min, $max)
    {
        for ($time = $min; $time < $max; ++$time) {
            yield [
                $time
            ];
        }
    }
}

请注意使用expects()和其他约束如何设置多个期望值。所有这些都可以很容易地结合起来。

供参考,见: