我一直在使用PHPUnit一段时间,但突然碰上了一堵墙:嘲笑LDAP。我有一个小的抽象层,用于使用默认的LDAP PHP扩展与LDAP服务器通信。现在,我不知道如何模拟扩展的连接和功能,以便正确测试我的类。
文件系统和数据库模拟很常见且易于设置,但目录服务器呢? :(
答案 0 :(得分:5)
您应该模拟LDAP适配器,而不是PHP扩展。文件系统和数据库模拟以相同的方式工作......它们实际上并不创建文件系统或数据库,它们只代表通常与这些数据源交互并模仿某些行为的类,就好像它确实存在一样。
例如:
// Load user 12345
$user = UserModel::find(12345);
通常情况下,此调用将发送到数据库并查询用户12345.但是,我们已经模拟了PDO适配器,并告诉它在query()
或execute()
方法时响应数据使用预期参数调用。因此,虽然看起来我们已经模拟了整个数据库,但我们所做的一切都是模拟最接近数据库但离您自己的代码最远的类。
希望您使用的是具有LDAP适配器的身份验证系统,您可以使用模拟替换它。或者是PHP的ldap函数的包装类。
<强>更新强>
最大的问题是你几乎在每种方法中使用基本的ldap函数。代码确实没问题..但单元测试很难。我通过创建一个处理所有通信的方法来解决这个问题并对此做出了断言:
(免责声明:此代码没有逻辑意义,根本不起作用..仅用于示例目的)
class LDAP_Auth {
public function authenticate($username, $password) {
// Extra business logic or other things that need to be tested
return $this->_callLdap('ldap_bind', $username, $password);
}
protected function _callLdap() {
$args = func_get_args();
$functionName = array_shift($args); // First argument should be the function name
return call_user_func_array($functionName, $args);
}
}
因此,每个ldap_*
函数都是从同一个_callLdap()
方法调用的。如果您想测试authenticate()
方法,那么您只需要:
_callLdap
方法并声明它使用正确的参数调用一次authenticate()
这样的事情:
$ldapMock = $this->getMock('LDAP_Auth', array('_callLdap');
$ldapMock->expects($this->once())
->method('_callLdap')
->with(array('ldap_bind', 'mike', 'password'))
->will($this->returnValue(true));
$ldapMock->authenticate('mike', 'password');
此测试断言使用params _callLdap
调用array('ldap_bind', 'mike', 'password')
方法,确保authenticate()
正常运行
答案 1 :(得分:1)
或者,您可以使用UnboundID Ldap SDK内存服务器来创建功能正常的目录服务器以进行测试。另见:In memory Directory Server。