vimeo / php-mysql-engine
用PHP编写的MySQL引擎,用于加速测试
Requires
- php: ^7.1|^8
- ext-pdo: *
- nyholm/dsn: ^2.0
- symfony/polyfill-php73: ^1.22
Requires (Dev)
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.5
- vimeo/psalm: ^4.6
README
PHP MySQL Engine 是一个PHP库,允许您通过内存中MySQL 5.6的模拟来测试数据库驱动应用程序。该项目扩展了 PDO
类,并允许您调用常见的PDO MySQL方法。它支持广泛的查询,以及一些PDO特定的功能,如事务和不同的获取模式。
PHP MySQL Engine 基于Slack的由 Scott Sandler 创建的 Hack SQL Fake。
您可以在这里阅读有关此工具的文章 这里。
动机
目前有两种方法来测试读取和写入数据库的代码
-
模拟SQL查询执行
模拟需要显式列出预期的查询及其返回结果。这会导致大量的手动设置预期的工作,并且测试脆弱且必须更新代码或查询的良性更改。这也意味着数据访问层没有进行单元测试。 -
使用实际的数据库
使用单独的数据库实例进行测试可能是有意义的——这是我们在Vimeo过去所做的事情。但是,MySQL之类的数据库是为了填充大量持久数据而设计的,而单元测试则写入少量非常短暂的数据。这意味着必须格外小心,确保测试数据库在测试之间被截断,这会引发性能问题。
PHP MySQL Engine 采用不同的方法 - 它解析并执行针对存储在PHP数组中的内存中“数据库”的 SELECT
、INSERT
、UPDATE
和 DELETE
查询。只要用于测试的数据量很小,这就可以解决上述问题。
支持的SQL语法
此库支持广泛的查询语法,包括
FROM
、WHERE
、GROUP BY
、HAVING
、ORDER BY
、LIMIT
子句,根据每种查询类型相应地支持- 所有类型的连接查询
- 多查询,如子查询、
UNION
、UNION ALL
、INTERSECT
、EXCEPT
- 复杂的表达式,如
CASE
、BETWEEN
和行比较符(1, 2, 3) < (4, 5, 6)
- 所有基本运算符均按运算符优先级实现
- 列别名,跨数据库查询
INSERT ... ON DUPLICATE KEY UPDATE
- 各种SQL函数,如
COUNT()
、NULLIF()
、COALESCE()
、CONCAT_WS()
等 - 临时变量,如
@previous_name := user.name
- 验证解析器:查询解析器将在大多数无效的SQL查询上抛出异常,帮助保护您的生产环境免受意外的SQL语法错误的影响
不支持的MySQL功能
此引擎不支持MySQL存储对象,这排除了对存储过程、触发器和视图的测试。
告示
与Psalm不同,这个包并不是面向广大用户设计的。为了使项目真正受益于这个库,该项目应该已经拥有大量需要数据库连接才能完成的测试,并且项目的维护者必须理解在使用测试套件中的非官方MySQL实现时相关的权衡。
已知问题
不模拟预处理语句的结果类型
默认情况下,引擎将所有数据格式化为字符串。如果调用$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false)
,则引擎将相反地推断列类型(例如,SUM(some_int_column)
将被赋予int
类型)。在某些情况下,php-mysql-engine
可能在推断正确的列类型方面比实际的MySQL做得更好,MySQL默认将列类型设置为字符串。如果您对结果进行严格的类型检查,您可能会看到一些小的差异。
安装
composer require --dev vimeo/php-mysql-engine
使用方法
PHP MySQL Engine通过提供PDO的一个子类来工作。
您可以像使用PDO
一样实例化子类,并通过依赖注入或类似的方法将该实例提供给您的应用程序代码。
// use a class specific to your current PHP version (APIs changed in major versions) $pdo = new \Vimeo\MysqlEngine\Php8\FakePdo($dsn, $user, $password); // currently supported attributes $pdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
其余的代码可以按正常方式操作,使用数据库的方式与生产环境中相同。
为什么它不支持X?
这个库的目标是支持用户在MySQL中使用的所有内容,而不是MySQL提供的所有可能的功能。我们欢迎提交拉取请求来添加对新语法、SQL函数、数据类型、错误修复和其他特性的支持。
为什么这个项目没有问题跟踪器?
维护开源项目是一项艰巨的工作,我不想给自己或我的同事增加更多的工作。请自行承担使用此项目的风险。
如果您想使用问题跟踪器分叉此项目,请随时操作!
贡献
如果您想创建一个PR,请确保它通过了单元测试
vendor/bin/phpunit
以及Psalm的检查
vendor/bin/psalm
谢谢!