我有各种PHP脚本,它们使用mysqli
函数集来访问数据库。我编写了这些脚本来处理各种错误情况(例如mysqli_stmt_execute
返回false)。
有没有一种简单的方法可以伪造这些错误条件,以验证用户收到的输出是否适合这些条件?
如果您使用的是mysqli类
例如:
<?php
$mysqli = new mysqli("localhost", "user", "password", "db");
$query = "INSERT INTO some_table (some_field) VALUES ('some_vale')";
$stmt = $mysqli->prepare($query);
if (false === $stmt->execute()) {
echo "Oops! some_value for same_field in some_table returned false";
}
模拟类并覆盖语句执行
<?php
class my_mysqli extends mysqli
{
public function prepare ($query)
{
return new my_mysqli_stmt();
}
}
class my_mysqli_stmt extends mysqli_stmt {
public function execute ()
{
return false;
}
}
要使每个execute方法都返回false,您只需要更改:
<?php
$mysqli = new my_mysqli("localhost", "user", "password", "db");
如果您使用的是函数
例如:
<?php
$mysqli = mysqli_connect("localhost", "user", "password", "db");
$query = "INSERT INTO some_table (some_field) VALUES ('some_vale')";
$stmt = mysqli_prepare($mysqli, $query);
if (false === mysqli_stmt_execute($stmt)) {
echo "Oops! some_value for same_field in some_table returned false";
}
命名空间php>=5.3中的Monkey补丁
<?php
namespace my_faking_namespace {
function mysqli_stmt_execute($stmt)
{
return false;
}
$mysqli = mysqli_connect("localhost", "user", "password", "db");
$query = "INSERT INTO some_table (some_field) VALUES ('some_vale')";
$stmt = mysqli_prepare($mysqli, $query);
if (false === mysqli_stmt_execute($stmt)) {
echo "Oops! some_value for same_field in some_table returned false";
}
}
您的脚本将调用my_faking_namespace'mysqli_stmt_execute()
,而不是php版本。
注意:如果您调用像'mysqli_stmt_execute()
这样的函数,这将不起作用,因为此版本显式调用全局命名空间。
不那么容易的替代方案,用于完成目的
这些函数在调用堆栈级别修改函数,通过使用自定义扩展模块在内部更改php(需要安装)。
- 高级PHP调试器有
override_function()
和rename_function()
- runkit有
runkit_function_copy
、runkit_function_redefine
、runkit_function_remove
和runkit_function_rename
,可以更改任何您想要的内容
nJoy!
如果您正在寻找自动化测试,最好的方法(使用PHP)是PHPUnit。
使用PHPUnit,您可以编写单元测试(特别是断言),它允许您验证用户接收的输出是否适用于每种不同的条件。
如果您不在生产环境中,最好的方法是更改PHP中的各种数据库参数。
- 更改数据库密码以查看如何处理连接错误
- 修改表结构以查看如何处理查询错误
- 试着看看查询中的特殊字符(例如:буква)会发生什么
也许您问错了问题:为什么您的核心业务逻辑依赖于第三方库/API?你听说过所谓的洋葱建筑吗?更多地按照域、业务、基础设施/测试这几条线对应用程序进行分层,可以让您更容易地测试不会改变的东西:业务逻辑。
然而,由于PHP是一种动态类型语言,mocking本质上是免费的。只要您使用的是OO功能而不是全局函数,那么创建可测试代码所需要的就是在代码中注入假数据库句柄。一个很好的方法是将$db
参数添加到函数/方法中。像这样琐碎的事情:
function updateStuff($rowIds, $newValues, $db) { ... }
然后,在涵盖updateStuff
的单元测试中,传入一个mock对象作为$db
参数。