php - 对接受字符串参数以创建 PDO 对象的 PHP 类进行单元测试

标签 php mysql unit-testing pdo phpunit

我有一个类 ( PDOMySQLForeignKeysToURLsService ),它的作用与它所说的完全一样,它采用 JSON 编码的数据库实体,将其与配置文件进行比较,并将任何外键字段转换为链接到其他 RESTful 资源的 URL。即

[
  {
    "ID": "1",
    "person_id": "1",
    "pc_name": "my_computer"
  }
]

假设person_id是数据库中的外键,会变成类似

[
  {
    "ID": "1",
    "person_id": "http://localhost/api/db/person/1",
    "pc_name": "my_computer"
  }
]

因为该服务本身是从配置文件初始化的,所以它只能在其构造函数中接受文本,

public function __construct(string $pdoDSN, string $username, string $password, string $tablename, string $schemaname)

一切似乎都运行得很好,但现在我想为这个类编写一些单元测试,其中一部分需要 PDO对象被实例化并且 INFORMATION_SCHEMA查询表如下

  SELECT 
    *
  FROM
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE
  WHERE
    TABLE_SCHEMA = ? AND
    CONSTRAINT_NAME != "PRIMARY" AND
    REFERENCED_TABLE_NAME IS NOT NULL AND
    REFERENCED_COLUMN_NAME IS NOT NULL

发生这种情况的方法是在接口(interface) Resolvable 的实现中,定义function resolveRequest(ServiceRequest $request, ServiceResponse $response)

除了在测试设置中设置模式/一些表之外,我基本上不知道如何测试所有这些?我从同行那里听说这是不好的做法,并不构成单元测试,而是集成测试 - 所以我的问题是我如何才能对这种方法进行单元测试,单元测试在这里是否合适?根据定义,该类非常依赖于 MySQL(和 PDO)。我是否应该围绕 PDO 编写某种适配器并使用 DI 框架来注入(inject)它,并与之交互而不是直接使用 PDO?说实话,我很迷茫,不知道该做什么,并且不明白这个想法/如何模拟仅在方法范围内使用的依赖项

最佳答案

即使您无法注入(inject) PDO 实例,仍然有方法对其进行单元测试 - 它只需要一点创造力。对您所描述的内容进行单元测试的最简单方法可能是创建一个允许注入(inject)的可测试子类。确切的细节取决于您的类的实现方式,但一个简单的示例可能如下所示:

class PDOMySQLForeignKeysToURLsService {
    protected $pdo;

    public function __construct(string $pdoDSN, string $username, string $password, string $tablename, string $schemaname) {
        $this->pdo = $this->createPdo(...);
    }

    // Encapsulate the PDO creation so that the subclass can override it.
    protected function createPdo(...) {
        return new PDO(...);
    }

    // Other methods omitted...
}

class TestablePDOMySQLForeignKeysToURLsService extends PDOMySQLForeignKeysToURLsService {
    // Override the constructor so you can pass in a mock PDO as the last parameter
    public function __construct(string $pdoDSN, string $username, string $password, string $tablename, string $schemaname, PDO $pdo) {
        // Save the injected mock PDO instance.
        $this->pdo = $pdo;
        parent::__construct(...);
    }

    // Override the creation so that you can just use the injected mock.
    protected function createPdo(...) {
        return $this->pdo;
    }
}

TestablePDOMySQLForeignKeysToURLsService 类将位于您的测试旁边,您将在测试用例中使用它而不是生产类。这个想法是“可测试”类是生产类的最小扩展 - 刚刚足以让您注入(inject)测试 double 。这使您可以测试生产类的逻辑并在测试中模拟数据库调用,而无需更改生产类的接口(interface)。这有点作弊,但它完成了工作。

关于php - 对接受字符串参数以创建 PDO 对象的 PHP 类进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51207499/

相关文章:

mysql - 返回 3 个月内的所有记录 (MySQL)

c# - DbC(按契约(Contract)设计)和单元测试

java - 对调用外部服务的类进行单元测试

unit-testing - 你如何在 TCl 中测试私有(private)方法

php - 使用不同的模型/页面插入一行 - CodeIgniter

php - Laravel - 在数据库中的一列中插入动态图像数组 JQuery

mysql - 如何选择今天最受欢迎的行

php - preg_split 以逗号分隔,忽略括号,PHP

javascript - 网站不加载布局

mysql - 如何将复杂的 MySQL 查询转换为 Doctrine2