Yes, you can do it
There are two approaches that you could take to this. Both have their drawbacks given the code sample you provided.
I'm going to assume that mysql_query()
is a typo, and you meant mysqli_query()
. See How can I prevent SQL injection in PHP? for more info on why you should not be using the mysql_*
functions and what you can do instead.
Use dependency injection
Given your statement
Where prMysql is a wrapper class written for mysql operations
I am, for the purposes of this part of the answer, going to assume that the calls such as mysql_query($sql, $connection)
are actually written as $prMysql->query($sql)
, thus wrapping the actual call. I'm also going to assume that the num_results()
part is done in that method too. If you opt for this refactoring solution, the prMysql
class will need to be used for querying, as well as just the connection.
The idea behind dependency injection is that you don't instantiate the dependencies (prMysql
in your case) inside the class that is using it, but outside of it. This comes in useful when it comes to unit testing because you can give a fake, or "mock" object to the class that is under test. This mock object can be constructed such that it always returns a known value to a known input.
The downside in your case of this approach is that you will need to refactor the ProjectHandler
class to have this passed as a dependency. Something like the following should suffice, but you might need to play around with where you have the open connection call:
class ProjectHandler
{
/** @var prMysql */
private $database;
/**
* @param prMysql $database
*/
public function __construct(prMysql $database)
{
$this->database = $database;
}
/**
* @param mixed $projectId
* @return array
*/
public function getProjectInformation($projectId)
{
$prMysql = $this->database;
$sql = sprintf("SELECT product_id, projectName FROM test_projects
WHERE projectId = %d", $platform_id);
$test_row = $pyMysql->query($sql);
return $test_row;
}
}
What this means is that you can easily give a mock prMysql
object while testing without having to change any of the code of the system under test. In your test method you could then have something like the following:
public function testGetProjectInformation()
{
// Here, we create a mock prMysql object so we don't use the original
$prMysql = $this->getMockBuilder(prMysql::class)
->disableOriginalConstructor()
->getMock();
/* Here, we say that we expect a call to mysql_query with a given query,
* and when we do, return a certain result.
* You will also need to mock other methods as required */
$expectedQuery = "SELECT product_id, projectName FROM test_projects
WHERE projectId = 1";
$returnValue = [['product_id' => 1, 'projectName' => 'test Name']];
$prMysql->expects($this->once())
->method('query')
->with($this->equalTo($expectedQuery))
->willReturn($returnValue);
// Here we call the method and do some checks on it
$object = new ProjectHandler($prMysql);
$result = $object->getProjectInformation(1);
$this->assertSame($returnValue, $result);
}
Now, please remember that this is just a rough sketch of what you need to do. You will need to fill in the details yourself. There's a fair amount of refactoring to do, but it will be worth it in the end.
Set up a mock database
The other alternative is to set up a database just for testing, and connect directly to this.
There is a whole chapter in the phpunit manual about this, but what it boils down to is, for each test:
- Setting the database to a known state
- Running the test
- Asserting that certain tables are in a given state
- Tearing down the connection
In your case this has the advantage that you will have to change little, if any, of your code. This has the disadvantage that your tests will be very slow, and you have lost the abstraction that dependency injection etc. would give.