是的,你可以做到的
您可以采取两种方法来解决这个问题。鉴于您提供的代码示例,两者都有其缺点。
我假设mysql_query() 是一个错字,而您的意思是mysqli_query()。请参阅How can I prevent SQL injection in PHP?,了解有关为什么不应该使用mysql_* 函数以及可以做些什么的更多信息。
使用依赖注入
鉴于你的陈述
其中 prMysql 是为 mysql 操作编写的包装类
出于这部分答案的目的,我将假设诸如mysql_query($sql, $connection) 之类的调用实际上写为$prMysql->query($sql),从而包装了实际调用。我还将假设num_results() 部分也是用这种方法完成的。如果您选择此重构解决方案,prMysql 类将需要用于查询,以及仅用于连接。
dependency injection 背后的想法是,您不会在使用它的类内部而是在它外部实例化依赖项(在您的情况下为 prMysql)。当涉及到单元测试时,这很有用,因为您可以为正在测试的类提供一个假的或“模拟”对象。可以构造此模拟对象,使其始终向已知输入返回已知值。
这种方法的缺点是您需要重构 ProjectHandler 类以使其作为依赖项传递。类似以下的内容就足够了,但您可能需要在打开连接调用的位置进行调整:
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;
}
}
这意味着您可以在测试时轻松地模拟prMysql 对象,而无需更改被测系统的任何代码。在您的测试方法中,您可能会有如下内容:
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);
}
现在,请记住,这只是您需要做什么的粗略草图。您需要自己填写详细信息。有相当多的重构工作要做,但最终还是值得的。
设置模拟数据库
另一种选择是建立一个仅用于测试的数据库,然后直接连接到该数据库。
There is a whole chapter 在 phpunit 手册中对此进行了说明,但归结为,对于每个测试:
- 将数据库设置为已知状态
- 运行测试
- 断言某些表处于给定状态
- 断开连接
在您的情况下,这样做的好处是您只需对代码进行少量更改(如果有的话)。这样做的缺点是您的测试会非常慢,并且您已经失去了依赖注入等所提供的抽象。