如何在 SQL INSERT 语句上使用 PHPUnit 获取模拟和 PDO
How to get a mock & PDO working with PHPUnit on a SQL INSERT statement
我有一个名为 ip_requestTest.php
的测试 class,它具有以下功能:
public function testSetTimestampCount()
{
$validData = [
'id' => '99',
'ip' => '127.0.0.1',
'timestamp' => '2021-06-03 10:28:43.000'
];
$table = 'ip';
$stmt = $this->createMock(\PDOStatement::class);
$stmt->expects($this->once())
->method('execute')
->with($validData)
->willReturn(true);
global $pdo;
$pdo = $this->createMock('PDO');
$pdo->expects($this->once())
->method('prepare')
->with("INSERT INTO {$table} id,address,timestamp VALUES (:ip, :id, :timestamp)")
->willReturn($stmt);
$ipStmt = new ip_request();
$ipStmt->setTimestampCount($validData);
}
现在最后一行是问题所在,$ipStmt->setTimestampCount($validData);
我的实际 setTimestampCount() 函数不只接受一个参数。
看起来像这样:
function setTimestampCount($ip,$id,$conn)
{
$query = $conn->prepare ("INSERT INTO `ip` (`id`, `address` ,`timestamp`)VALUES (:id,:ip,CURRENT_TIMESTAMP)");
$query ->bindValue(':id', $id, PDO::PARAM_INT);
$query ->bindValue(':ip', $ip, PDO::PARAM_STR);
$query->execute();
}
任何人都可以帮助我,或者给我任何关于如何正确测试此功能的线索吗?
如何将数据包含到测试函数调用中?
谢谢
更新 1:
尝试了 splat 运算符的建议,还删除了时间戳插入,因为这可以通过插入数据自动完成。
还是不行,我得到的错误是
Too few arguments to function 2 passed, exactly 3 expected.
我显然知道这是什么意思,但是 splat 运算符如何处理这个问题?如果有的话?
您的方法 setTimestampCount($ip,$id,$conn)
需要这 3 个参数。
你传入的3是$validData
的内容,即
'id' => '99',
'ip' => '127.0.0.1',
'timestamp' => '2021-06-03 10:28:43.000'
相反,您需要从该数组中删除时间戳参数,并将其替换为您的模拟连接。
其次,您正在这样做:
$stmt->expects($this->once())
->method('execute')
->with($validData)
->willReturn(true);
但是 execute
方法没有参数:
$query->execute();
它也没有 return 任何东西(或者至少你没有将它 return 的任何东西分配给一个变量),所以没有必要做 ->willReturn(true);
所以上面应该只是:
$stmt->expects($this->once())
->method('execute');
测试时间戳也没有意义。您应该做的就是检查您传递给 prepare
方法的字符串。所以你需要检查两个字符串看起来是否相同。目前您正在测试的字符串是:
"INSERT INTO `ip` (`id`, `address` ,`timestamp`)VALUES (:id,:ip,CURRENT_TIMESTAMP)"
并且您指定
"INSERT INTO {$table} id,address,timestamp VALUES (:ip, :id, :timestamp)
所以诸如缺少 (
、)
、参数之间的间距差异等都会导致此测试失败。它们必须相同。
最后,您实际上并没有测试 ip
和 id
或时间戳值是什么。 prepare
语句实际上并没有使用它们;它只有字符串 :id,:ip,CURRENT_TIMESTAMP
.
您还应该真正测试 bindValue
方法,它确实使用了 ip 和 id 值。由于您要调用它两次,这会稍微复杂一些,但是您可以使用 PHPUnit's withConsecutive
method 来处理这个问题:
$stmt->expects($this->exactly(2))
->method('bindValue')
->withConsecutive(
[':id', $id, PDO::PARAM_INT],
[':ip', $ip, PDO::PARAM_STR]
);
所以我认为该方法应该如下所示:
public function testSetTimestampCount()
{
$table = 'ip';
$id = '99';
$ip => '127.0.0.1';
$stmt = $this->createMock(\PDOStatement::class);
$stmt->expects($this->once())
->method('execute');
$stmt->expects($this->exactly(2))
->method('bindValue')
->withConsecutive(
[':id', $id, PDO::PARAM_INT],
[':ip', $ip, PDO::PARAM_STR]
);
$pdo = $this->createMock('PDO');
$pdo->expects($this->once())
->method('prepare')
->with("INSERT INTO `ip` (`id`, `address` ,`timestamp`)VALUES (:id,:ip,CURRENT_TIMESTAMP)")
->willReturn($stmt);
$validData = [
'id' => $id,
'ip' => $ip,
'conn' => $pdo
];
$ipStmt = new ip_request();
$ipStmt->setTimestampCount(...$validData);
}
我有一个名为 ip_requestTest.php
的测试 class,它具有以下功能:
public function testSetTimestampCount()
{
$validData = [
'id' => '99',
'ip' => '127.0.0.1',
'timestamp' => '2021-06-03 10:28:43.000'
];
$table = 'ip';
$stmt = $this->createMock(\PDOStatement::class);
$stmt->expects($this->once())
->method('execute')
->with($validData)
->willReturn(true);
global $pdo;
$pdo = $this->createMock('PDO');
$pdo->expects($this->once())
->method('prepare')
->with("INSERT INTO {$table} id,address,timestamp VALUES (:ip, :id, :timestamp)")
->willReturn($stmt);
$ipStmt = new ip_request();
$ipStmt->setTimestampCount($validData);
}
现在最后一行是问题所在,$ipStmt->setTimestampCount($validData);
我的实际 setTimestampCount() 函数不只接受一个参数。
看起来像这样:
function setTimestampCount($ip,$id,$conn)
{
$query = $conn->prepare ("INSERT INTO `ip` (`id`, `address` ,`timestamp`)VALUES (:id,:ip,CURRENT_TIMESTAMP)");
$query ->bindValue(':id', $id, PDO::PARAM_INT);
$query ->bindValue(':ip', $ip, PDO::PARAM_STR);
$query->execute();
}
任何人都可以帮助我,或者给我任何关于如何正确测试此功能的线索吗?
如何将数据包含到测试函数调用中?
谢谢
更新 1:
尝试了 splat 运算符的建议,还删除了时间戳插入,因为这可以通过插入数据自动完成。
还是不行,我得到的错误是
Too few arguments to function 2 passed, exactly 3 expected.
我显然知道这是什么意思,但是 splat 运算符如何处理这个问题?如果有的话?
您的方法 setTimestampCount($ip,$id,$conn)
需要这 3 个参数。
你传入的3是$validData
的内容,即
'id' => '99',
'ip' => '127.0.0.1',
'timestamp' => '2021-06-03 10:28:43.000'
相反,您需要从该数组中删除时间戳参数,并将其替换为您的模拟连接。
其次,您正在这样做:
$stmt->expects($this->once())
->method('execute')
->with($validData)
->willReturn(true);
但是 execute
方法没有参数:
$query->execute();
它也没有 return 任何东西(或者至少你没有将它 return 的任何东西分配给一个变量),所以没有必要做 ->willReturn(true);
所以上面应该只是:
$stmt->expects($this->once())
->method('execute');
测试时间戳也没有意义。您应该做的就是检查您传递给 prepare
方法的字符串。所以你需要检查两个字符串看起来是否相同。目前您正在测试的字符串是:
"INSERT INTO `ip` (`id`, `address` ,`timestamp`)VALUES (:id,:ip,CURRENT_TIMESTAMP)"
并且您指定
"INSERT INTO {$table} id,address,timestamp VALUES (:ip, :id, :timestamp)
所以诸如缺少 (
、)
、参数之间的间距差异等都会导致此测试失败。它们必须相同。
最后,您实际上并没有测试 ip
和 id
或时间戳值是什么。 prepare
语句实际上并没有使用它们;它只有字符串 :id,:ip,CURRENT_TIMESTAMP
.
您还应该真正测试 bindValue
方法,它确实使用了 ip 和 id 值。由于您要调用它两次,这会稍微复杂一些,但是您可以使用 PHPUnit's withConsecutive
method 来处理这个问题:
$stmt->expects($this->exactly(2))
->method('bindValue')
->withConsecutive(
[':id', $id, PDO::PARAM_INT],
[':ip', $ip, PDO::PARAM_STR]
);
所以我认为该方法应该如下所示:
public function testSetTimestampCount()
{
$table = 'ip';
$id = '99';
$ip => '127.0.0.1';
$stmt = $this->createMock(\PDOStatement::class);
$stmt->expects($this->once())
->method('execute');
$stmt->expects($this->exactly(2))
->method('bindValue')
->withConsecutive(
[':id', $id, PDO::PARAM_INT],
[':ip', $ip, PDO::PARAM_STR]
);
$pdo = $this->createMock('PDO');
$pdo->expects($this->once())
->method('prepare')
->with("INSERT INTO `ip` (`id`, `address` ,`timestamp`)VALUES (:id,:ip,CURRENT_TIMESTAMP)")
->willReturn($stmt);
$validData = [
'id' => $id,
'ip' => $ip,
'conn' => $pdo
];
$ipStmt = new ip_request();
$ipStmt->setTimestampCount(...$validData);
}