Я пишу несколько модульных тестов и застрял в том, что сначала считал ошибкой, но после большого разочарования кажется, что это было запланировано (но невозможно найти документацию/упоминание о) поведении/использовании.
Минимальный примерный случай выглядит так:
class UpdateListener()
{
public function handleStatusChange(UpdateUpdated $event): void
{
//checks various conditions of $event and modifies $successful_update_at
}
}
class CandidateTest extends TestCase
{
public function testSuccessfulUpdateTimestampManagement(): void
{
$updateListener = new UpdateListener();
//The first test verifies that a new timestamp is set
//when creating a mock with second argument set "true"
$updateEvent = $this->mockUpdateEvent(UpdateEvent::class, true);
$updateListener->handleStatusChange($updateEvent);
$this->assertEquals('2024-05-19', $candidate->successful_update_at->format('Y-m-d'));
//The second test sets "false" on the second argument and expects null on the attribute
$updateEvent = $this->mockUpdateEvent(UpdateEvent::class, false);
$updateListener->handleStatusChange($updateEvent);
$this->assertNull($candidate->successful_update_at);
}
private function mockUpdateEvent(string $class, bool $findsPreviousUpdate): UpdateEvent
{
$mockUpdate = \Mockery::mock(Update::class);
$mockUpdate->makePartial();
$previousSuccessfulUpdate = new Update();
$previousSuccessfulUpdate->register_date = '2024-05-19';
$mockQueryBuilder = \Mockery::mock(Builder::class);
$mockQueryBuilder->shouldReceive('getResult')->andReturn(
$findsPreviousUpdate ? $previousSuccessfulUpdate : null
);
$mockUpdate->shouldReceive('query')->andReturn($mockQueryBuilder);
return new $class($mockUpdate);
}
}
Итак, в этом минимальном примере происходит то, что я (или мне так казалось) создаю чистые макеты класса, который использует построитель запросов (laravel 11, если это имеет какое-либо значение). ), чтобы «найти» объект при определенных условиях и использовать временную метку этого объекта на макете субъекта. При некоторых условиях я ожидаю возврата null и использую этот второй флаг аргумента, чтобы сообщить макету, что он должен возвращать.
Однако именно здесь мы добираемся до «Проблемы»: второе утверждение никогда не является нулевым, макет всегда возвращает $previousSuccessfulUpdate независимо от того, что я говорю ему вернуть при создании макета.
Поэтому, посмотрев на то, что делает макеты::mock и ->andReturn, становится ясно, что под капотом происходит какое-то повторное использование макетных объектов и ожидание возврата. >
Как правильно выполнить такое утверждение на одном и том же имитируемом объекте, ожидая при этом разных результатов от имитируемых методов? Я упускаю что-то основное, что заставило бы это работать так, как я ожидаю? Разделение утверждений на разные тесты, чтобы получить своего рода «TearDown» для сброса моих макетов?
Поскольку ->andReturn, похоже, использует «очередь» возвращаемых ответов, я получаю ожидаемые утверждения, просто передавая ему различные ожидаемые возвращаемые значения в том порядке, в котором я их ожидаю. Это похоже на очень «жестко запрограммированный» способ сделать это и подразумевает, что я должен знать точный порядок и количество возвратов, которые, как я ожидаю, даст любой тест для любого макета. Я бы предпочел иметь возможность в любой момент времени точно указать, что именно должен возвращать макет, изменяя его всякий раз, когда я считаю нужным...?
$mockQueryBuilder->shouldReceive('getResult')->andReturn($previousSuccessfulUpdate, null);
Подробнее здесь: https://stackoverflow.com/questions/785 ... in-phpunit
Путаница по поводу повторного использования макета в phpunit ⇐ Php
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Есть ли разница в названии файла конфигурации PHPunit phpunit.xml.dist или phpunit.xml?
Anonymous » » в форуме Php - 0 Ответы
- 69 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Путаница по поводу виртуальных подклассов при проверке статического типа, например mypy
Anonymous » » в форуме Python - 0 Ответы
- 16 Просмотры
-
Последнее сообщение Anonymous
-