首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为执行mysql调用的类在phpunit中编写单元测试?

问如何为执行mysql调用的类在phpunit中编写单元测试?
EN

Stack Overflow用户
提问于 2016-11-30 10:51:43
回答 1查看 3.3K关注 0票数 1

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

代码语言:javascript
复制
<?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调用吗?

EN

回答 1

Stack Overflow用户

发布于 2016-12-01 19:24:29

是的,你能做到的

你可以采取两种方法来解决这个问题。考虑到您提供的代码示例,两者都有各自的缺点。

我假设mysql_query()是一个错误,您的意思是mysqli_query()。有关为什么不应该使用mysql_*函数以及您可以做什么的更多信息,请参见mysql_*。

使用依赖注入

考虑到你的陈述

其中,prMysql是为mysql操作编写的包装类。

为了回答这一部分的目的,我将假设像mysql_query($sql, $connection)这样的调用实际上是以$prMysql->query($sql)的形式编写的,从而包装了实际的调用。我还将假设num_results()部分也是用该方法完成的。如果您选择此重构解决方案,则需要使用prMysql类进行查询,以及仅用于连接。

依赖注入背后的思想是,您不会在使用它的类中实例化依赖项(在您的情况下是prMysql),而是实例化它之外的依赖项。当涉及到单元测试时,这是很有用的,因为您可以向正在测试的类提供一个假的或“模拟”对象。可以构造这个模拟对象,以便它总是将已知的值返回给已知的输入。

这种方法的缺点是,需要重构ProjectHandler类才能将其作为依赖项传递。下面这样的内容就足够了,但是您可能需要在有打开连接调用的地方玩一玩:

代码语言:javascript
复制
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对象,而不必更改被测试系统的任何代码。在您的测试方法中,您可以得到如下内容:

代码语言:javascript
复制
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);
}

现在,请记住,这只是一个粗略的草图,你需要做什么。你需要自己填写细节。有相当多的重构要做,但最终还是值得的。

建立模拟数据库

另一种选择是只为测试而建立一个数据库,并直接连接到这个数据库。

关于这一点,phpunit手册中的有整整一章,但其归结为,对于每个测试:

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

在您的情况下,这具有这样的优势,即您必须对代码进行很少的更改(如果有的话)。这有一个缺点,即您的测试将非常慢,并且您已经失去了依赖注入等提供的抽象。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40886429

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档