mockery overload properties
/ 3 min read
Table of Contents
mockery 是個好東西,你可以輕易的 mock instance ,好讓你在寫 test 的時候不會捶心肝。但總是有些地方總是無法符合我的需求,所以才有了這個 package
mockery overload properties,這算是加強 mockery 的功能。因為之前在寫 test case 的時候,有時候會遇到像是下面的寫法:
User.php
class User{ public $id; public $isVip; public $rank;
/** * construct */ public function __construct($id) { // some global static function $dbh = DB_INSTANCE::getCurrent(); $sql = " SELECT id, isVip, rank FROM user WHERE id = :id "; $stm = $dbh->prepare($sql); $bind = $stm->bindValue(':id', $id, PDO::PARAM_INT); $stm->execute(); $user = $stm->fetch(PDO::FETCH_ASSOC);
$this->id = $user['id']; $this->isVip = $user['isVip']; $this->rank = $user['rank']; }}
Vip.php
class Vip{ /** * check user is vip or not * * @return boolean is vip */ public function bonus($userId) { $defaultBonus = 100; $user = new User($userId);
if ($user->isVip) { $bonus = $defaultBonus * $user->rank + 55; } else { $bonus = $defaultBonus * 0.5 + $user->rank; } return $bonus; }}
在 Vip
的 function bonus
裡,使用 new User
的方式取得資料庫的資料,User
在 __construct
的時候會把值設給 public properties,所以如果要用 Mockery 去 overload instance 的時候,會無法 mock User
的 properties,就會變成不得不在 test 的時候 insert 一筆資料進 user table,可以參考這個 test case。
解決方式
如果不打算重構改由 DI 的方式來寫 test case 的話,可以參考這個 來寫 test case,這樣測試 Vip
的時候,即使是 User
是 hard dependencies,也可以簡單 mock。
如果想用簡單的 DI 來處理的話,在這 example code 裡就要改為:
class Vip{ /** * check user is vip or not * * @return boolean is vip */ public function bonus(User $user) { $defaultBonus = 100; if ($user->isVip) { $bonus = $defaultBonus * $user->rank + 55; } else { $bonus = $defaultBonus * 0.5 + $user->rank; } return $bonus; }}
在 function bonus
傳入 User
instance,而不是一個 $userId
,這樣的話你就可以隨意的 mock User
instance 了。