简体   繁体   English

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

[英]PHPUnit mock return value and number of times called with specific argument for different methods same class

My scenario is similar to below: 我的情况类似于以下内容:

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);
        }
    }
}

Now, I want to test if ToMock::iReturn() returns 150, ToTest::feedMe() calls ToMock::callMe1() once with 5 and 10, and ToMock::callMe2() once with 15 and 20. 现在,我想测试ToMock::iReturn()返回150, ToTest::feedMe() ToMock::callMe1()以5和10调用ToMock::callMe1() ,以及ToMock::callMe2()以15和20 ToMock::callMe2()

I know I can mock the ToMock::iReturn to return 150, also I can mock ToMock to expect a particular method once with supplied argument. 我知道我可以模拟ToMock::iReturn返回150,也可以模拟ToMock使用提供的参数来期待一次特定的方法。 But, is it possible to do all of these together in the same time? 但是,是否可以同时进行所有这些操作? if yes, how would it look like? 如果是,它看起来如何?

If I understood your question correctly then test code could look like 如果我正确理解了您的问题,则测试代码可能如下所示

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);
    }
}

Yes, it is. 是的。

Here's an example of a test that covers ToTest : 这是涵盖ToTest的测试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
            ];
        }
    }
}

Note how multiple expectations are set up using expects() and further constraints. 注意如何使用expects()和更多约束来设置多个期望。 All of these can be easily combined. 所有这些都可以轻松组合。

For reference, see: 供参考,请参阅:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM