Почему тестирование запросов PUT и PATCH платформы API не работает, но API работает с теми же операциями с пользовательсPhp

Кемеровские программисты php общаются здесь
Ответить
Anonymous
 Почему тестирование запросов PUT и PATCH платформы API не работает, но API работает с теми же операциями с пользовательс

Сообщение Anonymous »

Я использую объекты Doctrine в базе данных, которые сопоставляются с DTO службами с помощью метода getComponentDtoFromEntity($comComponent), чтобы представить их на платформе API 3.2 в Symfony 7.1 и PHP 8.3. У каждого DTO есть маршрут с необходимыми HTTP-глаголами, который позволяет мне работать только с нужными мне данными, иметь несколько конечных точек, использующих один и тот же объект (с разными DTO), иметь составные DTO (сочетание нескольких объектов) и никогда не раскрывать напрямую мои объекты.
Я создал некоторый DTO, напрямую связанный с платформой API, например:

Код: Выделить всё

#[ApiResource]
#[Get(
uriTemplate: 'stock/components/{id}',
read: true,
provider: ComponentDtoProviderService::class,
)]
#[GetCollection(
uriTemplate: 'stock/components/',
provider: ComponentDtoProviderService::class
)]
#[Post(
uriTemplate: 'stock/components/',
validationContext: ['groups' => ['Default', 'postValidation']],
processor: ComponentDtoProcessorService::class,
)]
#[Delete(
uriTemplate: 'stock/components/{id}',
provider: ComponentDtoProviderService::class,
processor: ComponentDtoProcessorService::class
)]
#[Put(
uriTemplate: 'stock/components/',
validationContext: ['groups' => ['Default']],
processor: ComponentDtoProcessorService::class
)]
readonly class ComponentDto
{
public function __construct(
public ?string $id,
#[Assert\NotBlank(groups: ['postValidation'])]
public string $name,
public ?string $ean13,
public ?int $quantity,
public ?int $quantityThreshold,
) {
}
}
Когда я использую встроенный тест API по адресу /api, все работает нормально при каждой операции (GET, POST, PUT, DELETE).
Я использую PHPunit для тестирования своего API, поэтому я создал тесты для операций get, getAll, post, delete и put/patch, используя ранее добавленные фикстуры (которые я получаю по имени).

Код: Выделить всё

    public function testComponentsPut(): void
{
$componentBlueRose = $this->componentRepository->findByName(ComponentFixtures::COMPONENT_BLUE_ROSE);
self::assertNotNull($componentBlueRose);

// test new EAN13 and quantity and quantityThreshold
$componentBlueRoseDtoModified = new ComponentDto(
$componentBlueRose->getId()->toString(),
$componentBlueRose->getName(),
'9234569990123', // data are modified here
400, // data are modified here
8, // data are modified here
);

$response = parent::createClient()->request('PUT', 'api/stock/components/',
['json' => $componentBlueRoseDtoModified]);

self::assertResponseIsSuccessful();
$componentBlueRoseUpdated = $this->componentRepository->findByName(ComponentFixtures::COMPONENT_BLUE_ROSE);

// todo : its not working here
self::assertSame($componentBlueRoseDtoModified->ean13, $componentBlueRoseUpdated->getEan13());
self::assertSame($componentBlueRoseDtoModified->quantity, $componentBlueRoseUpdated->getQuantity());
self::assertSame($componentBlueRoseDtoModified->quantityThreshold, $componentBlueRoseUpdated->getQuantityThreshold());
}
Предыдущие тесты проводились с помощью Get, Post, Delete и GetAll, и все работает нормально, но не в случае PUT и PATCH: когда я получаю сохраненные данные в базе данных, данные никогда не изменялся. Для тестирования я беру объект в базе данных, сопоставляю его с DTO, затем изменяю DTO и отправляю его в API с помощью команды PUT (я также делал то же самое с PATCH). Затем я получаю объект с тем же идентификатором в базе данных и сравниваю свойства обоих объектов, чтобы убедиться, что изменения сохранены. Но это не так.
Это заставило меня обнаружить странное поведение платформы API:
Когда вызываются операции PATCH или PUT, всегда вызывается поставщик, даже если он не указан, и он вызывается ДО того, как процессорная ведьма, на самом деле так и делает:
  • DTO с новыми модификациями передается в HTTPRequest следующим образом:

    Код: Выделить всё

          $response = $client->request('PUT', 'api/stock/components/',
    ['json' => $componentBlueRoseDtoModified]);
    
  • Этот DTO перехватывается классом Provider, который принимает идентификатор, загружает новый объект из базы данных и отображает его как DTO, что правильное поведение операции GET. DTO, возвращаемый поставщиком, взят из базы данных, поэтому это не модифицированный DTO, указанный в HTTP-запросе.
  • Этот DTO передается процессору, который сохраняет его.
Проблема в том, что Процессор сохраняет DTO, взятый из базы данных, а не тот, который указан в первое место, и изменения никогда не сохраняются.
Поскольку я знаю, что при указании /{id} для операций исправления и размещения требуется поставщик (в последних версиях платформы API), я попробовал оба пути:
  • /api/comComponent/{id} с указанным поставщиком и процессором и
  • /api/ компонент/ без поставщика
    Он работает точно так же: тестирование напрямую с /api работает, но не в модульных тестах.
Вот Код провайдера:

Код: Выделить всё

public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|ComponentDto
{
// get all components
if ($operation instanceof CollectionOperationInterface) {
$components = $this->componentRepository->getAll();
$componentDtos = [];
foreach ($components as $component) {
$componentDtos[] = $this->getComponentDtoFromEntity($component);
}

return $componentDtos;
}

// get one component
if (!isset($uriVariables['id'])) {
throw new \Exception('Id is required');
}
$component = $this->componentRepository->findByIdAsString($uriVariables['id']);

if (null === $component) {
throw new \Exception('Component not found');
}

return $this->getComponentDtoFromEntity($component);
}

public function getComponentDtoFromEntity(Component $component): ComponentDto
{
return new ComponentDto(
$component->getId() === null ? null : (string) $component->getId(),
$component->getName(),
$component->getEan13(),
$component->getQuantity(),
$component->getQuantityThreshold(),
);
}
Ну, вопросы такие:
  • Почему PATCH и PUT работают на самом деле, но не в модульных тестах? Как заставить это работать?
  • Почему провайдер вызывается, даже если в атрибутах платформы API указан ТОЛЬКО процессор?


Подробнее здесь: https://stackoverflow.com/questions/788 ... works-with
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Php»