我想重构我的模型,所以我可以正确地为它编写单元测试。但我有一些依赖。任何人都可以指出我正确的方向如何删除这些依赖项?
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;
}
}
答案 0 :(得分:2)
我猜你的依赖项是函数体中的构造函数调用。我不介意在单元测试中有3种方法可以替换它们:
public function save(array $data, $id = NULL, $newCustomer=\Entities\Customer(), $newLangModel = Application_Model_Language, ...)
。同样在函数体中,您可以使用变量来创建实际对象,例如$customer = new $newCustomer()
。在测试代码中,您可以通过模拟类覆盖每个依赖的类。您不为每个类添加参数,但创建两个factories:一个创建当前对象,另一个创建模拟对象。在函数内部,您只能从工厂请求新对象。
如果有许多不同的地方需要拦截施工,这种方法很有用。如果只有一个功能需要更改,则工厂过度工程。
答案 1 :(得分:0)
回顾一下你的代码之后,看来这个类充当了\ Entities \ Customer类的工厂和存储库(这不是很明显,所以你可以考虑重命名以更明确地表达你的意图)。我也不同意这个名为save的函数,因为它只返回一个需要持久保存的对象,但这更具语义性。
使用现在的代码,我看到了需要的两个不同的测试。
1)测试您的\ Entities \ Customer类。
验证您的每个getter和setter是否正常工作,或者至少知道任何具有业务逻辑的getter和setter。例如,如果您设置了ResellerShop,请确保获得正确/有效的ResellerShow对象。 或多或少,您需要测试您的业务逻辑。获取/设置基本字段(例如姓名)并不需要他们自己的测试(除非100%的代码覆盖率是一个目标,我认为不是)。
2)测试(Factory \ Repository)类。
确保您显示的类正确创建(或失败),具体取决于传入阵列的数据。例如,如果未传入必填字段,则它应该失败,并且它不应返回客户实体对象。
这个想法是为了分离关注点。您的Entity类应该包含您的业务逻辑,并且应该与对象实例化代码分开测试。