Задать вопрос
first-programmer
@first-programmer
Backend software engineer

Как тестировать код, где функции в основном ничего не возвращают?

Всем привет, есть у меня такой кусок кода, кто может подсказать на его примере, как вообще такое тестировать? Тут все функции ничего не возвращают, а просто что-то выполняют (добавляют в базу данных записи, отправляют запросы в апи, отправляют сообщение в очередь)

final class PartnerApiOfdTicketHandler implements MessageHandlerInterface
{
    private OfdTicketMessage $ofdTicketMessage;
    private OfdTicketService $ofdTicketService;
    private OrangeApiOfdTicketService $orangeApiOfdTicketService;
    private OfdTicketStatusProducer $ofdTicketStatusProducer;
    private LoggerInterface $logger;

    public function __construct(
        OfdTicketService $ofdTicketService,
        OrangeApiOfdTicketService $orangeApiOfdTicketService,
        OfdTicketStatusProducer $ofdTicketStatusProducer,
        LoggerInterface $logger
    ) {
        $this->ofdTicketService = $ofdTicketService;
        $this->orangeApiOfdTicketService = $orangeApiOfdTicketService;
        $this->ofdTicketStatusProducer = $ofdTicketStatusProducer;
        $this->logger = $logger;
    }

    public function __invoke(OfdTicketMessage $ofdTicketMessage): void
    {
        $this->logger->info(
            'OfdTicketMessage was received',
            ['data' => $ofdTicketMessage->toArray()]
        );

        $this->ofdTicketMessage = $ofdTicketMessage;

        try {
            $this->ofdTicketService->create($ofdTicketMessage);
            $this->orangeApiOfdTicketService->createTicket($ofdTicketMessage);

            $this->ofdTicketService->update(
                $ofdTicketMessage,
                [
                    'processed' => true,
                    'statusCode' => OrangeApiResponseStatus::TICKET_CREATED
                ]
            );

            $this->ofdTicketStatusProducer->push(new OfdTicketStatusMessage($ofdTicketMessage->toArray()));
        } catch (ConflictException $e) {
            $this->handleException($e, 'Need to ack message because: ');

            throw new  UnrecoverableMessageHandlingException($e->getMessage(), $e->getCode());
        } catch (OfdOrangeApiException $e) {
            $this->handleException($e, 'Ofd orange api error: ', [
                'error' => 'Ofd orange api error: ' . $e->getMessage(),
                'statusCode' => $e->getCode()
            ]);
        } catch (TransportExceptionInterface $e) {
            $this->handleException($e, 'Can\'t send request to ofd orange api: ', [
                'error' => 'Can\'t send request to ofd orange api: ' . $e->getMessage(),
                'statusCode' => $e->getCode()
            ]);
        } catch (\Exception|\Throwable $e) {
            $this->handleException($e, 'Something went wrong: ', [
                'error' => 'Something went wrong: ' . $e->getMessage(),
                'statusCode' => InternalExceptionStatus::INTERNAL_ERROR
            ]);

            throw new  UnrecoverableMessageHandlingException($e->getMessage(), $e->getCode());
        }
    }


Это код обработчика сообщений из очереди.

$this->ofdTicketService->create($ofdTicketMessage); - сохранят сообщение в базу данных
 $this->orangeApiOfdTicketService->createTicket($ofdTicketMessage); - создает тикет через стороннее api, тело ответа в положительном сценарии всегда пустое, просто приходит код 201, при негативном возникает исключение и тело ответа с ошибкой.

обновляем статус в базе данных
$this->ofdTicketService->update(
    $ofdTicketMessage,
         [
             'processed' => true,
             'statusCode' => OrangeApiResponseStatus::TICKET_CREATED
         ]
    );

Отправляем в очередь.
$this->ofdTicketStatusProducer->push(new OfdTicketStatusMessage($ofdTicketMessage->toArray()));


Я в тестировании совсем не шарю. Посмотрел разные видео, почитал документацию, пока не понимаю, как проверять такой код. Я понимаю проверить assert что функция вернулся что-то, но тут функции ничего не возвращают. мокать объекты через $this->createMock тоже смысла нет, так как по сути тогда все методы будут пустыми, а чтобы проверить работоспособность такого кода, по сути нужно

1. Создать тестовую базу данных и накатить миграции.
2. Создать объект сообщения со своими данными, просто через new.
3. Передать его в метод настоящего, не замоканого сервиса $this->ofdTicketService->create($ofdTicketMessage), чтобы тот по настоящему сохранил его в тестовую базу данных.
4. Дальше не знаю, но может есть какие-то методы типа assertExistsInDatabaseTable.
5. $this->orangeApiOfdTicketService->createTicket($ofdTicketMessage) обращение к api вообще не понятно, как тестировать именно в этом случае, и нужно ли вообще? По сути правильной работой его можно считать, если этот метод не выбросит исключение.
6. Проверить обновился ли статус в базе данных.
7. С отправкой в очередь не понятно.

Буду благодарен, если поможете разобраться. Можно тут, можно в конфе, можем договориться в лс.
  • Вопрос задан
  • 256 просмотров
Подписаться 1 Средний 1 комментарий
Помогут разобраться в теме Все курсы
  • Skillbox
    Веб-разработчик на PHP
    9 месяцев
    Далее
  • Хекслет
    PHP-разработчик
    10 месяцев
    Далее
  • Нетология
    Веб-разработчик с нуля: профессия с выбором специализации
    14 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 2
SilenceOfWinter
@SilenceOfWinter Куратор тега PHP
та еще зажигалка...
ты можешь тестировать метод на срабатывание исключений + проверить те свойства что он изменяет + проверить ээ по английски это backside effect т.е. внение изменения произошедшие в результате выполнения плагина.
вообще не всегда можно написать тест, например, нельзя протестировать mail() т.к. нельзя проверить дошло ли письмо до адресата.
Ответ написан
Если речь о Модульном тестировании - замокать всё зависимости и пройтись по всем сценариям убедившись что всё идёт по плану. Суть моков в том что вы можете проверять что будет приходить в пустые методы, указывать что они будут возвращать, или при необходимости, бросать исключение.

Если хотите проверить что в итоге сохранится в базу - это уже будет ближе к EndToEnd тестированию. В таком случае можно поднять тестовую базу, и наполнить всеми необходимыми данными, а для проверок описать свои Assert-ы которые будут ходить в базу и проверять что там лежит.

Следует учитывать что если проект активно развивается - для него будет естественным переживать периодические рефакторинги, что с высокой вероятностью будет вынуждать к переписыванию Unit-тестов. Функциональные и EndToEnd тесты наоборот - позволят рефакторить всё что только можно, обновлять зависимости и PHP как только будут выходить stable версии, и при этом быть уверенным что тестируемые сценарии всё ещё работают как вы задумывали.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
FoodSoul Калининград
от 180 000 до 250 000 ₽
IT-Spirit Москва
от 230 000 до 320 000 ₽
IT ATLAS Москва
от 250 000 до 500 000 ₽