I want to refactor my model so I can properly write a unit test for it. But I have some dependencies. Can anybody point me in the right direction how I can remove these dependencies?
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;
}
}
I guess your dependencies are the constructor calls in the function body. Out of my mind there are 3 ways to replace them in the unit test:
Create a mock library where all the different classes are implemented, and to run the test include the mock library instead of the real modules.
Add a set of default parameters for the external classes to your function declaration. In the end your new function declaration would look like
public function save(array $data, $id = NULL, $newCustomer=\Entities\Customer(), $newLangModel = Application_Model_Language, ...). Also in the function body you use the variables to create the actual objects, like$customer = new $newCustomer(). In the test code you can override every depended class by a mock class.You do not add a parameter for every class, but create two factories: one which creates the current objects, and one which creates mock objects. Inside of the function you request new objects only from the factory.
This approach is useful if there are many different places where the construction should be intercepted. If there is only one function which should be changed, a factory is over-engineering.