Рефакторинг модели для целей тестирования - PullRequest
2 голосов
/ 24 сентября 2010

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

class Customer
{
    public function save(array $data, $id = NULL)
    {
        // create or update
        if (empty($id)) {
            $customer = new \Entities\Customer();
        } else {
            $customer = $this->findById((int) $id);
        }

        $birthday = new DateTime();
        list($day, $month, $year) = explode("/", $data['birthday']);
        $birthday->setDate($year, $month, $day);

        $customer->setFirstName($data['firstName']);
        $customer->setLastName($data['lastName']);
        $customer->setCompany($data['company']);
        $languageModel = new Application_Model_Language();
        $customer->setLanguage($languageModel->findById($data['language']));
        $resellerShopModel = new Application_Model_ResellerShop();
        $customer->setResellerShop($resellerShopModel->findById($data['resellerShop']));
        $customer->setEmail($data['email']);
        $customer->setPhone($data['phone']);
        $customer->setGender($data['gender']);
        $customer->setBirthday($birthday);
        $customer->setType($data['type']);
        $customerSectorModel = new Application_Model_CustomerSector();
        $customer->setSector($customerSectorModel->findById($data['sector']));
        $customerReferenceModel = new Application_Model_CustomerReference();
        $customer->setReference($customerReferenceModel->findById($data['reference']));
        if (isset($data['password'])) {
            $customer->setPassword($this->_hashPassword($data['password']));
        }

        return $customer;
    }
}

Ответы [ 2 ]

2 голосов
/ 29 сентября 2010

Полагаю, ваши зависимости - это вызовы конструктора в теле функции. На мой взгляд, есть 3 способа заменить их в модульном тесте:

  1. Создайте фиктивную библиотеку , в которой реализованы все различные классы, и для запуска теста включите фиктивную библиотеку вместо реальных модулей.
  2. Добавьте набор параметров по умолчанию для внешних классов в объявление вашей функции. В конце ваша новая декларация функции будет выглядеть как public function save(array $data, $id = NULL, $newCustomer=\Entities\Customer(), $newLangModel = Application_Model_Language, ...). Также в теле функции вы используете переменные для создания реальных объектов, например $customer = new $newCustomer(). В тестовом коде вы можете переопределить каждый зависимый класс с помощью фиктивного класса.
  3. Вы не добавляете параметр для каждого класса, но создаете две фабрики : одну, которая создает текущие объекты, и одну, которая создает фиктивные объекты. Внутри функции вы запрашиваете новые объекты только с завода.

    Этот подход полезен, если есть много разных мест, где конструкция должна быть перехвачена. Если есть только одна функция, которую следует изменить, фабрика перегружена.

0 голосов
/ 30 сентября 2010

После просмотра вашего кода кажется, что этот класс действует как Фабрика и Репозиторий для класса \ Entities \ Customer (это было неочевидно, поэтому вы могли бы рассмотреть переименование как более явное в своих намерениях). Я также не согласен с тем, что эта функция называется save, так как она возвращает только объект, который затем необходимо сохранить, но это больше семантика.

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

1) Проверьте свой класс \ Entities \ Customer.

Убедитесь, что каждый из ваших геттеров и сеттеров работает правильно, или хотя бы любой из них имеет бизнес-логику. Например, убедитесь, что если вы установите ResellerShop, то если вы получите правильный / действительный объект ResellerShow. Более или менее, вам нужно проверить свою бизнес-логику. Получение / набор базовых полей (например, Name) на самом деле не требуют их собственных тестов (если только 100% охват кода не является целью, я так не думаю).

2) Проверьте класс (Factory \ Repository).

Убедитесь, что класс, который вы показали, правильно создается (или не работает) в зависимости от данных, передаваемых в массив. Например, он должен завершиться ошибкой, если обязательные поля не переданы, и он не должен возвращать объект сущности клиента.

Идея заключается в разделении интересов. Ваш класс Entity должен содержать вашу бизнес-логику и должен тестироваться отдельно от кода реализации вашего объекта.

...