gpt4 book ai didi

phpunit - 如何在 phpunit 中为调用 mysql 的类编写单元测试?

转载 作者:行者123 更新时间:2023-12-03 09:12:27 29 4
gpt4 key购买 nike

我有一个执行 mysql 操作的示例类,如下所示。

<?php
class ProjectHandler{
public function getProjectInformation($projectId){
$prMysql = new prMysql;
/* Make connection to database */
$connection = $prMysql->open_store_database();
$sql = sprintf("SELECT product_id, projectName FROM test_projects
WHERE projectId = %d", $platform_id);
$test_result = mysql_query($sql, $connection) or die();
$num_rows = mysql_num_rows($test_result);
if ($num_rows > 0) {
$test_row = mysql_fetch_assoc($test_result);
}
return $test_row;
}
}
?>

其中prMysql是为mysql操作编写的包装类。是否可以模拟场景中的mysql调用?

最佳答案

是的,你可以做到

您可以采用两种方法来实现此目的。鉴于您提供的代码示例,两者都有其缺点。

我假设mysql_query()是一个拼写错误,而您的意思是mysqli_query()。请参阅How can I prevent SQL injection in PHP?了解有关为什么不应使用 mysql_* 函数以及可以做什么的更多信息。

使用依赖注入(inject)

鉴于您的陈述

Where prMysql is a wrapper class written for mysql operations

为了这部分答案的目的,我假设诸如 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 手册中有关于这一点的内容,但它归结为,对于每个测试:

  • 将数据库设置为已知状态
  • 运行测试
  • 断言某些表处于给定状态
  • 断开连接

就您而言,这样做的优点是您只需更改很少的代码(如果有的话)。这样做的缺点是您的测试会非常慢,并且您已经失去了依赖注入(inject)等所提供的抽象。

关于phpunit - 如何在 phpunit 中为调用 mysql 的类编写单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40886429/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com