PHPUnit具有连续的奇怪行为

时间:2016-08-18 14:47:16

标签: php object phpunit

考虑下一个测试:

class User
{
}

class UserRepository
{
    public function getByName($name)
    {
    }

    public function getByUser(User $user)
    {
    }
}

class UserController
{
    private $userRepository;

    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function findByNames($name1, $name2)
    {
        $this->userRepository->getByName($name1);
        $this->userRepository->getByName($name2);
    }

    public function findByUsers($user1, $user2)
    {
        $this->userRepository->getByUser($user1);
        $this->userRepository->getByUser($user2);
    }
}

class WithConsecutiveTest extends \PHPUnit_Framework_TestCase
{
    /**
     * This test is fails if some of "Alice" or "Bob" string changed. This is expected behaviour.
     */
    public function testWithConsecutiveOnStrings()
    {
        $name1 = 'Alice';
        $name2 = 'Bob';

        $userRepository = $this->createMock(UserRepository::class);

        $userRepository
            ->expects($this->exactly(2))
            ->method('getByName')
            ->withConsecutive(
                [$name1], // change to $name2 and test fails
                [$name2]
            );

        $userController = new UserController($userRepository);
        $userController->findByNames($name1, $name2);
    }

    /**
     * This test is NOT fails if in "withConsecutive()" call $user1 changed to $user2. This is unexpected behaviour.
     */
    public function testWithConsecutiveOnObjects()
    {
        $user1 = $this->createMock(User::class);
        $user2 = $this->createMock(User::class);

        $this->assertEquals($user1, $user2);
        $this->assertNotSame($user1, $user2);

        $userRepository = $this->createMock(UserRepository::class);

        $userRepository
            ->expects($this->exactly(2))
            ->method('getByUser')
            ->withConsecutive(
                [$user1], // change to $user2 and test is also passed
                [$user2]
            );

        $userController = new UserController($userRepository);
        $userController->findByUsers($user1, $user2);
    }
}

使用“withConsecutive()”的字符串参数进行的第一次测试是正常的,但是对象的第二次测试会产生一些魔力:类似于两个对象的弱比较的东西在这里,所以在任何情况下都会传递第二个测试。

我试过“[$ this->回调(函数($ user1arg)使用($ user1)){return $ user1arg === $ user1}]”约束 - 这很好用,但写了很多这个约束是一种某种猴子的工作。

也许它可能有一个更简单的解决方案,而不是用对象的$ this->回调(...)编写很多约束?

1 个答案:

答案 0 :(得分:1)

并非PHPUnit中的所有内容都是完美的,但这应该对您有用。当然,财产'名称'只是一个例子。如果用户没有任何行为,则不需要模拟它。

class User
{
    private $name;

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName($name)
    {
        return $this->name;
    }
}

测试方法

public function testWithConsecutiveOnObjects()
{
    $user1 = new User();
    $user1->setName('Alice');
    $user2 = new User();
    $user2->setName('Bob');
    $this->assertNotEquals($user1, $user2);
    $this->assertNotSame($user1, $user2);
    $userRepository = $this->createMock(UserRepository::class);
    $userRepository
        ->expects($this->exactly(2))
        ->method('getByUser')
        ->withConsecutive(
            [$user1], //we are comparing values here, not references
            [$user2]
        );
    $userController = new UserController($userRepository);
    $userController->findByUsers($user1, $user2);
}