然而,因为书签类的构造函数调用了静态方法DB:conn()来获取数据库连接,要注入模拟连接到其中就很困难了。这儿有一些可能的实现方法:增加一个方法来改变$this->conn,增加一个可选参数到每一个方法中,或是增加一个参数到构造函数中。让我们选用最后一种方法:给Bookmark的构造函数增加一个可选的参数。
class Bookmark { // ... public function __construct($id=false, $conn=false) { $this->conn = ($conn) ? $conn : DB::conn(); // ... } } |
现在,新的Bookmark依然能正常工作,但新的Bookmark(1, $connection)用参数中的$connection对象代替正常的ADOConnection对象。
当这段代码完成后,你就能方便的将正常的数据库连接对象用模拟的连接对象进行替换,并且能进行数据库错误的检测。
class ActiveRecordTestCase extends UnitTestCase { // ... function testDbFailure() { $conn = new MockADOConnection($this); $conn->expectOnce(‘execute’, array(‘*’,’*’)); $conn->setReturnValue(‘execute’,false); $conn->expectOnce(‘errorMsg’); $conn->setReturnValue(‘errorMsg’, ‘The database has exploded!!!!’); $link = new Bookmark(1,$conn); $this->assertErrorPattern(‘/exploded/i’); $conn->tally(); } |
动态记录实例ID
在前面的例子中,大多数属性都是公共的,然而,书签ID是受保护的,以其值被免意外更改(如果其值被意外更改,当你想更新书签数据的时候问题就出现了)。因为$ID是受保护的,因此增加一个辅助方法来获取其值。
class Bookmark { protected $id; //... public function getId() { return $this->id; } } |
怎样来测试它呢?
class ActiveRecordTestCase extends UnitTestCase { // ... function testGetId() { $this->add(‘http://php.net’, ‘PHP’, ‘PHP Language Homepage’, ‘php’); // second bookmark, id=2 $link = $this->add(‘http://phparch.com’, ‘php|architect’, ‘php|arch site’, ‘php’); $this->assertEqual(2, $link->getId()); } } |
如上,add()方法生并成保存数据,并通过getid()方法获取生成数据的ID值并验证其是相匹配的。
但是,如果你想用别的条件来验证所生成的数据而不仅仅是用书签的ID,或是你如何确保从数据库中返回的ID是正确的?用select语句根据给定的属性条件取得数据,并验证返回行的ID值是一个好的技术方法。
class ActiveRecordTestCase extends UnitTestCase { // ... function testGetId() { $this->add(‘http://php.net’, ‘PHP’, ‘PHP Language Homepage’, ‘php’); // second bookmark, id=2 $link = $this->add(‘http://phparch.com’, ‘php|architect’, ‘php|arch site’, ‘php’); $this->assertEqual(2, $link->getId()); $alt_test = $this->conn->getOne( “select id from bookmark where url = ‘http://phparch.com’”); $this->assertEqual(2, $alt_test); //alternatively $this->assertEqual($link->getId(), $alt_test); } } |
注意到这个试验类似于你用手工执行一个SQL查询来验证数据是否正确插入到书签表中。通过本次实验所实现代码,还能用于你后续实验中来验证数据的正确性,而不是仅仅简单的去执行它。
记录搜索
现在,我们已能实现保存书签对象到数据库,并且能根据书签ID从数据库中获取相应数据来重建书签对象。但是当ID值并不知道(通常情况也是这样)时会发生什么?或是你想通过如部分名称或是URL等相关值来搜索数据库,则更常见的解决方法是增加一个”finder”方法。
例如,你也许想使用findByUrl()方法查找与给定参数相类似的书签,下面的实验则能实现上述的要求。
class ActiveRecordTestCase extends UnitTestCase { // ... function testFindByUrl() { $this->add(‘http://blog.casey-sweat.us/’, ‘My Blog’, ‘Where I write about stuff’, ‘php’); $this->add(‘http://php.net’, ‘PHP’, ‘PHP Language Homepage’, ‘php’); $this->add(‘http://phparch.com’, ‘php|architect’, ‘php|arch site’, ‘php’); $result = Bookmark::findByUrl(‘php’); $this->assertIsA($result, ‘array’); $this->assertEqual(2, count($result)); $this->assertEqual(2, $result[0]->getId()); $this->assertEqual(‘php|architect’, $result[1]->name); } } |
该实验生成一些数据,查找URL中包含有“PHP”字样的行,并校检返回的书签对象数组中的字符。FindByUrl()之所以是一个静态方法,是因为你有可能在没的书签对象实例化的情况下进行该操作。(当然你也能将“查找“方法放到每一个对象中,但目前 “查找”方法仍然是书签类中的一个方法。)
延伸阅读:
从魔兽看PHP设计模式
《PHP设计模式介绍》导言
PHP设计模式介绍 第一章 编程惯用法
PHP设计模式介绍 第二章 值对象模式
PHP设计模式介绍 第三章 工厂模式
PHP设计模式介绍 第四章 单件模式
PHP设计模式介绍 第五章 注册模式
PHP设计模式介绍 第六章 伪对象模式
PHP设计模式介绍 第七章 策略模式
PHP设计模式介绍 第八章 迭代器模式
PHP设计模式介绍 第九章 观测模式
PHP设计模式介绍 第十章 规范模式
PHP设计模式介绍 第十一章 代理模式
PHP设计模式介绍 第十二章 装饰器模式
PHP设计模式介绍 第十三章 适配器模式