考虑下一个测试:
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->回调(...)编写很多约束?
答案 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);
}