<?php
class MyClass
{
protected $results;
public function __construct()
{
$dbconn = new DatabaseConnection('localhost','user','password');
$this->results = $dbconn->query('select name from mytable');
}
public function getFirstResult()
{
return $this->results[0];
}
}
在这里,为了测试对象的 fdfdfd 方法,我们最终需要建立一个数据库连接,给表添加一些记录,然后在测试之后清除所有这些资源。如果测试 fdfdfd完全不需要这些东西,那么这个过程可能太过于复杂。因此,我们要修改 清单 6所示的构造函数。
清单 6. 为忽略所有不必要的初始化逻辑而修改的类
<?php
class MyClass
{
protected $results;
public function __construct($init = true)
{
if ( $init ) $this->init();
}
public function init()
{
$dbconn = new DatabaseConnection('localhost','user','password');
$this->results = $dbconn->query('select name from mytable');
}
public function getFirstResult()
{
return $this->results[0];
}
}
我们重构了构造函数中大量的代码,将它们移到一个 init() 方法中,这个方法默认情况下仍然会被构造函数调用,以避免破坏现有代码的逻辑。然而,现在我们在测试过程中只能够传递一个布尔值 false 给构造函数,以避免调用 init()方法和所有不必要的初始化逻辑。类的这种重构也会改进代码,因为我们将初始化逻辑从对象的构造函数分离出来了。
<?php
class MyUserClass
{
public function getUserList()
{
$dbconn = new DatabaseConnection('localhost','user','password');
$results = $dbconn->query('select name from user');
sort($results);
return $results;
}
}
假设我们正在测试上面的 getUserList方法,但是我们的测试关注点是保证返回的 用户清单是按字母顺序正确排序的。在这种情况下,我们的问题不在于是否能够从数据库获取这些记录,因为我们想要测试的是我们是否能够对返回的记录进行排 序。问题是,由于我们是在这个方法中直接实例化一个数据库连接对象,所以我们需要执行所有这些繁琐的操作才能够完成方法的测试。因此,我们要对方法进行修 改,使这个对象可以在中间插入,如 清单 8所示。
清单 8. 这个类有一个方法会直接实例化另一个对象,但是也提供了一种重写的方法
<?php
class MyUserClass
{
public function getUserList($dbconn = null)
{
if ( !isset($dbconn) || !( $dbconn instanceOf DatabaseConnection ) ) {
$dbconn = new DatabaseConnection('localhost','user','password');
}
$results = $dbconn->query('select name from user');
sort($results);
return $results;
}
}
现在您可以直接传入一个对象,它与预期数据库连接对象相兼容,然后直接使用这个对象,而非创建一个新对象。您也可以传 入一个模拟对象,也就是我们在一些调用方法中,用硬编码的方式直接返回我们想要的值。在这里,我们可以模拟数据库连接对象的查询方法,这样我们就只需要返 回结果,而不需要真正地去查询数据库。进行这样的重构也能够改进这个方法,因为它允许您的应用程序在需要时插入不同的数据库连接,而不是只绑定一个指定的 默认数据库连接。