Модульное тестирование - не имеет смысла для меня

Я пытаюсь научиться модульному тестированию и у меня возникает следующая ситуация: я просто не могу разобраться:

  1. У меня есть модель: SalesOrder - какие модели заказов в интернет-магазине
  2. SalesOrder имеет свойство под названием gift_message_id
  3. Идентификатор подарочного сообщения является целочисленным значением и является внешним ключом для модели GiftMessage
  4. Модель GiftMessage имеет метод, который может взять модель заказа и правильно загрузить экземпляр GiftMessage на основе SalesOrder.

Я пытаюсь написать тест, который точно проверяет это поведение, но в итоге я получаю 2 макета: 1 для SalesOrder и 1 для GiftMessage, и это не имеет смысла. Что я здесь не так делаю?

Метод, который я пытаюсь проверить, выглядит следующим образом:

public function loadGiftMessageByOrderModel(SalesOrder $order)
{
    $giftMessageId = $order->getGiftMessageId();

    //if the order has a gift message id then load the gift message model and return it
    if ($giftMessageId !== false) {
        return new GiftMessage($giftMessageId);
    }
    return false;
}

Как это может быть проверено модулем, учитывая, что данные заказа и подарочного сообщения хранятся в базе данных.

2 ответа

Каждый раз, когда у вас есть метод, который вызывает конструктор, и в конструкторе выполняется нетривиальная работа, у вас возникают проблемы. Наилучший вариант, который я вижу из вышесказанного, состоит в том, чтобы вышеуказанный класс имел GiftMessageFactory пример. Затем вы можете смоделировать фабрику, чтобы проверить, что она вызывается с соответствующими значениями и соответствующим временем.

Как вы написали loadGiftMessageByOrderModel функции и объяснил конструктор GiftMessage, я не думаю, что вы можете легко модульное тестирование этого кода. Для того, чтобы провести чистое тестирование, вам нужно загрузить GiftMessage из БД в методе, который не является конструктором. Ваш конструктор не должен вызывать методы, которые взаимодействуют с базой данных. Другой класс или метод должен выполнить эту загрузку, а затем вызвать конструктор. Примерно как то так:

public function loadGiftMessageByOrderModel(SalesOrder $order)
{
    $giftMessageId = $order->getGiftMessageId();

    //if the order has a gift message id then load the gift message model and return it
    if ($giftMessageId !== false) {
        // $giftMessageLoader handles loading from the DB; it doesn't create a GiftMessage object
        $giftMessageRecord = $giftMessageLoader.loadById( $giftMessageId );
        // $giftMessageFactory actually calls the constructor to create a GiftMessage
        return $giftMessageFactory.createFromRecord( $giftMessageRecord );
    }
    return false;
}

Затем вы можете издеваться над $giftMessageLoader.loadById вызов, чтобы вы контролировали то, что возвращается из базы данных. Вы также сможете проверить, что $giftMessageFactory вызывает GiftMessage конструктор соответствующим образом и создает соответствующий объект.

Общий урок здесь заключается в том, что конструкторы должны быть простыми. Они могут проверять параметры, чтобы объект был построен правильно, но, вероятно, они не должны вызывать другие важные части вашего приложения.

Другие вопросы по тегам