Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking LDAP connection for PHPUnit Test Suite

Tags:

php

ldap

phpunit

I have been using PHPUnit for a while now, but suddenly hit a big wall: mocking LDAP. I have a small abstraction layer for communicating with an LDAP server using the default LDAP PHP extension. Right now, i have no idea on how to mock the connection and functionalities of the extension in order to properly test my class.

Filesystem and Database mocks are quite common and easy to setup, but what about directory servers? :(

like image 685
Klaus S. Avatar asked Sep 16 '26 01:09

Klaus S.


2 Answers

You should mock your LDAP adapter, not the PHP extension. Filesystem and Database mocks work the same way... they don't actually create file-systems or databases, they just represent the class that normally interacts with those data-sources and mimic certain behaviors as if there really existed.

For example:

// Load user 12345
$user = UserModel::find(12345); 

Normally, this call would go out to the database and query for user 12345. However, we've mocked the PDO adapter and told it to respond with data when its query() or execute() methods are invoked with expected parameters. So, while it appears that we've mocked the entire database, all we've really done is mocked the class closest to the database but furthest from your own code.

Hopefully you're using an authentication system with an LDAP adapter that you can swap out with a mock. Or a wrapper class for PHP's ldap functions.

Update

The big problem is that you're using basic ldap functions in almost every method. Not a problem with the code really.. but it's difficult to unit-test. I've gotten around that by creating a single method that takes care of all that communication and made my assertions against that:

(disclaimer: this code makes no logical sense and won't work at all.. only for example purposes)

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);
  }
}

So every ldap_* function is invoked from the same _callLdap() method. If you wanted to test the authenticate() method, all you would have to do is:

  • create a mock object of the class itself
  • mock the _callLdap method and assert that it was called once with the right arguments
  • then invoke authenticate() like you normally would

Something like this:

$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');

This test asserts that the _callLdap method is invoked once with params array('ldap_bind', 'mike', 'password') insuring that authenticate() is functioning properly

like image 73
Mike B Avatar answered Sep 17 '26 15:09

Mike B


Alternatively, ou could use the UnboundID Ldap SDK in-memory server to create a functioning directory server for test purposes. See also: In memory Directory Server.

like image 43
Terry Gardner Avatar answered Sep 17 '26 16:09

Terry Gardner