Я читал документы PHPUnit в Интернете и использовал средства сопоставления фиктивных объектов, но я не уверен, когда вы должны или не должны их использовать. Для приведенного ниже примера предположим, что у меня есть класс Foo, для которого я пишу тест:
Фу класс
<?php
class Foo {
public function isUserNamedTom(User $user):bool
{
return strtoupper($user->getName()) === 'TOM';
}
}
Мой тест
<?php
use PHPUnit\Framework\TestCase;
class FooTest extends TestCase {
public function testIsUserNamedTom():void
{
$userMock = $this->getMockBuilder(User:class)
->disableOriginalConstructor()
->getMock();
$userMock->expects($this->once())
->method('getName')
->willReturn('tom');
$fooService = new Foo();
$response = $fooService->isUserNamedTom($userMock);
$this->assertTrue($response);
}
}
Мой вопрос в том, должен ли я использовать $это->один раз() или нет в этом примере, и если нет, то по каким причинам.
Ваши тесты должны проверять выходные данные тестируемого метода с минимальными знаниями о реализации тестируемого метода. Вы хотите, чтобы тест потерпел неудачу, когда метод больше не делает то, что должен делать, но вы не хотите, чтобы он потерпел неудачу, когда метод делает правильную вещь другим способом.
В этом случае кажется неуместным для проверки isUserNamedTom(User $user)
, вызывается ли user->getName()
один раз, дважды или никогда. Важно только то, что isUserNamedTom(User $user)
возвращает true
тогда и только тогда, когда $user
имеет имя «tom», «Tom», «tOm» и т. д.
Поэтому: Нет, я бы не стал проверять здесь $this->once()
.
Я бы даже попытался обойтись без насмешек и вместо этого передать созданный объект пользователя. Но возможно ли это, зависит от вашего User
класса.
public function testIsUserNamedTom():void
{
$user = (new User())->setName('tom');
$this->assertTrue($fooService->isUserNamedTom($user));
}
По сути, при написании тестов всегда полезно спросить себя, при каких обстоятельствах вы хотите, чтобы они провалились. В вашем примере я предполагаю, что ваш тест не должен терпеть неудачу, если кто-то рефакторинг isUserNamedTom(User $user)
так, что метод больше не вызывает $user->getName()
(но, возможно, использует общедоступное свойство $user->name
).
@Kyle Я часто использую его, когда хочу убедиться, что какая-то дорогостоящая операция (запрос к базе данных, вызов API, ...) не выполняется чаще, чем ожидалось.
Теперь это имеет смысл. Я убежден, что подсчет вызовов методов в этом примере не является хорошей идеей. Я не уверен, когда вы захотите его использовать (например, $this->once(), $this->at(0), $this->atLeastOnce()).