Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking/Stubbing an Object of a class that implements arrayaccess in PHPUnit

Here is the constructor of the class I am writing a test suite for (it extends mysqli):

function __construct(Config $c)
{
    // store config file
    $this->config = $c;

    // do mysqli constructor
    parent::__construct(
        $this->config['db_host'],
        $this->config['db_user'],
        $this->config['db_pass'],
        $this->config['db_dbname']
    );
}

The Config class passed to the constructor implements the arrayaccess interface built in to php:

class Config implements arrayaccess{...}

How do I mock/stub the Config object? Which should I use and why?

Thanks in advance!

like image 227
AndyPerlitch Avatar asked May 15 '12 19:05

AndyPerlitch


People also ask

Which method is used to create a mock with PHPUnit?

PHPUnit provides methods that are used to automatically create objects that will replace the original object in our test. createMock($type) and getMockBuilder($type) methods are used to create mock object. The createMock method immediately returns a mock object of the specified type.

What is stub in PHPUnit?

Stubs are used with query like methods - methods that return things, but it's not important if they're actually called. $stub = $this->createMock(SomeClass::class); $stub->method('getSomething') ->willReturn('foo'); $sut->action($stub);

How do you mock in PHP?

PHP-Mock: mocking built-in PHP functions does not exist. PHP-Mock uses that feature by providing the namespaced function. I.e. you have to be in a non global namespace context and call the function unqualified: namespace foo; $time = time(); // This call can be mocked, a call to \time() can't.


1 Answers

If you can easily create a Config instance from an array, that would be my preference. While you want to test your units in isolation where practical, simple collaborators such as Config should be safe enough to use in the test. The code to set it up will probably be easier to read and write (less error-prone) than the equivalent mock object.

$configValues = array(
    'db_host' => '...',
    'db_user' => '...',
    'db_pass' => '...',
    'db_dbname' => '...',
);
$config = new Config($configValues);

That being said, you mock an object implementing ArrayAccess just as you would any other object.

$config = $this->getMock('Config', array('offsetGet'));
$config->expects($this->any())
       ->method('offsetGet')
       ->will($this->returnCallback(
           function ($key) use ($configValues) {
               return $configValues[$key];
           }
       );

You can also use at to impose a specific order of access, but you'll make the test very brittle that way.

like image 195
David Harkness Avatar answered Oct 05 '22 07:10

David Harkness