2010-09-24 2 views
2

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

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

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

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

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

0

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

С кодом, как у вас есть сейчас, я вижу два разных теста, которые необходимы.

1) Проверьте свой \ Entities \ Customer class.

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

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

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

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

Смежные вопросы