1

I am trying to write a function which its purpose is to test for a database connection. What it does is it instantiates a Database object, attempts to connect to the database and return the result.

The pseudo code looks like this

<?php

function testDatabaseLogin() {
    // Get the database connection information from a file
    // ...

    // Database is a class which stores the connection information passed,
    // When its connect() method is invoked, it tries to connect. nothing fancy
    $conn = new Database($host, $port, $username, $password);
    return $conn->connect(); // TRUE on success, FALSE otherwise
}

?>

This code snippet is a simplified version of my situation, but it should be suffice to illustrate my question.

I would like to know how I could use PHPUnit to mock the Database class in this example. What I want is I can

  1. Assert that the arguments when instantiating Database from this function is correct
  2. Stub the Database to control connect() to return TRUE or FALSE, so that I don't need to actually attempt to connect to a real database

I have searched around but I found that it seems like PHPUnit Mock object does not work in this way. Any help is appreciate. And at the bottom line, it is acceptable to change the function implementation if it helps to make the testing easier.

Thank you.

user7509214
  • 149
  • 2
  • 7
  • Not sure if this helps, but I asked a question which involved mocking PDO connections (https://stackoverflow.com/questions/46379109/testing-coverage-with-phpunit-and-pdo). You may just have to validate the parameters for a reasonable value as without connecting you can't check they actually are valid. – Nigel Ren Sep 29 '17 at 06:33
  • @NigelRen Thank you for your help. I think my situation is different from yours because your `DBAccess` class accepts the `PDO` object. So you can use PHPUnit to mock the `PDO` object and pass it. But in my case the `Database` object is instantiated inside the function, which means even I have a mock object I have no ways to pass it inside. So I am thinking if PHPUnit cannot handle this case and I should instead try to refactor the function to make it testable. – user7509214 Sep 29 '17 at 06:49
  • I think the general consensus is to be able to inject any dependencies to enable testing etc, https://stackoverflow.com/questions/130794/what-is-dependency-injection gives a lot more details. – Nigel Ren Sep 29 '17 at 06:56

1 Answers1

0

There's a trick i've used sometimes

<?php   
class MyClass
{
   public function databaseLogin() {
        $conn = $this->createDatabase();
           return $conn->connect(); // TRUE on success, FALSE otherwise
        }

   protected function createDatabase() {
        new Database($host, $port, $username, $password);
   }
} 

Then, create a "Class under test" that extends your class:

class MyClassUnderTest extends MyClass
{
   public function __construct($databaseMock)
   {
       $this->databaseMock = $databaseMock;
       parent::__construct();
   }
}

And then, in the test:

class MySuperTest
{
    public function testSomethingWitDatabase()
    {
        $databaseMock = $this->getMockBuilder(DataBase::class)
            ->disableOriginalConstructor()
            ->getMock();

        $classUnderTest = new MyClassUnderTest($databaseMock);
        $this->assertTrue($classunderTest->databaseLogin());
    }
}

So you are instantiating your Database object into a method that is overwritten by a class just created for testing.

Marçal Berga
  • 305
  • 1
  • 11