295 lines
8.6 KiB
PHP
295 lines
8.6 KiB
PHP
<?php
|
||
/**
|
||
* 华为支付客户端测试类
|
||
*/
|
||
|
||
namespace addon\huaweipay\tests;
|
||
|
||
use addon\huaweipay\data\sdk\HuaweiPayClient;
|
||
use think\facade\Log;
|
||
|
||
class HuaweiPayClientTest
|
||
{
|
||
/**
|
||
* 测试配置
|
||
* @var array
|
||
*/
|
||
protected $testConfig = [
|
||
'app_id' => 'test_app_id',
|
||
'merc_no' => 'test_merc_no',
|
||
'private_key' => 'tests/mock/cert/merchant_private_key.pem',
|
||
'huawei_public_key' => 'tests/mock/cert/huawei_public_key.pem',
|
||
'sandbox' => true
|
||
];
|
||
|
||
/**
|
||
* 运行所有测试
|
||
*/
|
||
public function runTests()
|
||
{
|
||
echo "开始测试华为支付客户端...\n";
|
||
|
||
try {
|
||
$this->testConstructSuccess();
|
||
$this->testConstructMissingConfig();
|
||
$this->testGenerateSign();
|
||
$this->testH5Pay();
|
||
$this->testOrderQuery();
|
||
$this->testRefund();
|
||
$this->testVerifySign();
|
||
|
||
echo "\n✅ 所有测试通过!\n";
|
||
return true;
|
||
} catch (\Exception $e) {
|
||
echo "\n❌ 测试失败:" . $e->getMessage() . "\n";
|
||
echo "错误位置:" . $e->getFile() . " 第" . $e->getLine() . "行\n";
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试构造函数 - 成功场景
|
||
*/
|
||
public function testConstructSuccess()
|
||
{
|
||
echo "测试构造函数成功场景...";
|
||
|
||
// 模拟证书文件
|
||
$this->createMockCertFiles();
|
||
|
||
try {
|
||
$client = new HuaweiPayClient($this->testConfig);
|
||
echo " ✅ 通过\n";
|
||
} catch (\Exception $e) {
|
||
throw new \Exception("构造函数测试失败: " . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试构造函数 - 缺少必要配置
|
||
*/
|
||
public function testConstructMissingConfig()
|
||
{
|
||
echo "测试构造函数缺少配置...";
|
||
|
||
// 测试缺少app_id
|
||
try {
|
||
$config = $this->testConfig;
|
||
unset($config['app_id']);
|
||
new HuaweiPayClient($config);
|
||
throw new \Exception("应该抛出缺少app_id的异常");
|
||
} catch (\Exception $e) {
|
||
if (strpos($e->getMessage(), '缺少必要配置:app_id') === false) {
|
||
throw new \Exception("异常信息不正确: " . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
echo " ✅ 通过\n";
|
||
}
|
||
|
||
/**
|
||
* 测试生成签名
|
||
*/
|
||
public function testGenerateSign()
|
||
{
|
||
echo "测试生成签名...";
|
||
|
||
$this->createMockCertFiles();
|
||
$client = new HuaweiPayClient($this->testConfig);
|
||
|
||
// 使用反射调用私有方法
|
||
$reflection = new \ReflectionClass($client);
|
||
$method = $reflection->getMethod('generateSign');
|
||
$method->setAccessible(true);
|
||
|
||
$params = [
|
||
'app_id' => 'test_app_id',
|
||
'merc_no' => 'test_merc_no',
|
||
'order_id' => 'test_order_001',
|
||
'amount' => 100,
|
||
'sign' => 'ignored'
|
||
];
|
||
|
||
// 测试签名不应该失败
|
||
try {
|
||
$sign = $method->invoke($client, $params);
|
||
$this->assertEquals(true, is_string($sign), "签名应该是字符串");
|
||
echo " ✅ 通过\n";
|
||
} catch (\Exception $e) {
|
||
throw new \Exception("签名生成测试失败: " . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试H5支付
|
||
*/
|
||
public function testH5Pay()
|
||
{
|
||
echo "测试H5支付...";
|
||
|
||
$this->createMockCertFiles();
|
||
|
||
// 模拟HTTP请求
|
||
$this->mockHttpRequest();
|
||
|
||
$client = new HuaweiPayClient($this->testConfig);
|
||
|
||
$params = [
|
||
'order_id' => 'test_order_001',
|
||
'amount' => 100,
|
||
'subject' => '测试商品',
|
||
'notify_url' => 'https://example.com/notify',
|
||
'return_url' => 'https://example.com/return'
|
||
];
|
||
|
||
// 由于无法真正发送HTTP请求,这里只测试参数验证
|
||
try {
|
||
// 尝试调用,实际环境可能需要模拟curl
|
||
$result = $client->h5Pay($params);
|
||
echo " ⚠️ 跳过实际HTTP请求测试\n";
|
||
} catch (\Exception $e) {
|
||
// 预期可能会有curl错误,这里只检查是否因为参数问题
|
||
if (strpos($e->getMessage(), '缺少必要参数') !== false) {
|
||
throw new \Exception("H5支付参数测试失败: " . $e->getMessage());
|
||
}
|
||
echo " ⚠️ 跳过实际HTTP请求测试\n";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试订单查询
|
||
*/
|
||
public function testOrderQuery()
|
||
{
|
||
echo "测试订单查询...";
|
||
|
||
$this->createMockCertFiles();
|
||
|
||
$client = new HuaweiPayClient($this->testConfig);
|
||
|
||
$params = [
|
||
'order_id' => 'test_order_001'
|
||
];
|
||
|
||
try {
|
||
// 尝试调用,实际环境可能需要模拟curl
|
||
$result = $client->orderQuery($params);
|
||
echo " ⚠️ 跳过实际HTTP请求测试\n";
|
||
} catch (\Exception $e) {
|
||
if (strpos($e->getMessage(), '缺少必要参数') !== false) {
|
||
throw new \Exception("订单查询参数测试失败: " . $e->getMessage());
|
||
}
|
||
echo " ⚠️ 跳过实际HTTP请求测试\n";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试退款
|
||
*/
|
||
public function testRefund()
|
||
{
|
||
echo "测试退款...";
|
||
|
||
$this->createMockCertFiles();
|
||
|
||
$client = new HuaweiPayClient($this->testConfig);
|
||
|
||
$params = [
|
||
'order_id' => 'test_order_001',
|
||
'refund_order_id' => 'refund_001',
|
||
'refund_amount' => 100
|
||
];
|
||
|
||
try {
|
||
// 尝试调用,实际环境可能需要模拟curl
|
||
$result = $client->refund($params);
|
||
echo " ⚠️ 跳过实际HTTP请求测试\n";
|
||
} catch (\Exception $e) {
|
||
if (strpos($e->getMessage(), '缺少必要参数') !== false) {
|
||
throw new \Exception("退款参数测试失败: " . $e->getMessage());
|
||
}
|
||
echo " ⚠️ 跳过实际HTTP请求测试\n";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 测试签名验证
|
||
*/
|
||
public function testVerifySign()
|
||
{
|
||
echo "测试签名验证...";
|
||
|
||
$this->createMockCertFiles();
|
||
$client = new HuaweiPayClient($this->testConfig);
|
||
|
||
// 使用反射调用私有方法
|
||
$reflection = new \ReflectionClass($client);
|
||
$method = $reflection->getMethod('verifySign');
|
||
$method->setAccessible(true);
|
||
|
||
$params = [
|
||
'app_id' => 'test_app_id',
|
||
'merc_no' => 'test_merc_no',
|
||
'order_id' => 'test_order_001',
|
||
'amount' => 100
|
||
];
|
||
|
||
// 由于无法真正验证签名,这里只测试方法是否存在
|
||
try {
|
||
// 传入空签名,预期会失败
|
||
$verified = $method->invoke($client, $params, '');
|
||
echo " ⚠️ 跳过实际签名验证测试\n";
|
||
} catch (\Exception $e) {
|
||
echo " ⚠️ 跳过实际签名验证测试\n";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建模拟证书文件
|
||
*/
|
||
private function createMockCertFiles()
|
||
{
|
||
// 确保mock证书目录存在
|
||
$certDir = __DIR__ . '/mock/cert/';
|
||
if (!is_dir($certDir)) {
|
||
mkdir($certDir, 0755, true);
|
||
}
|
||
|
||
// 创建模拟证书文件
|
||
$privateKeyPath = $certDir . 'merchant_private_key.pem';
|
||
$publicKeyPath = $certDir . 'huawei_public_key.pem';
|
||
|
||
if (!file_exists($privateKeyPath)) {
|
||
file_put_contents($privateKeyPath, '-----BEGIN PRIVATE KEY-----\nMOCK_PRIVATE_KEY_CONTENT\n-----END PRIVATE KEY-----');
|
||
}
|
||
|
||
if (!file_exists($publicKeyPath)) {
|
||
file_put_contents($publicKeyPath, '-----BEGIN PUBLIC KEY-----\nMOCK_PUBLIC_KEY_CONTENT\n-----END PUBLIC KEY-----');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 模拟HTTP请求
|
||
*/
|
||
private function mockHttpRequest()
|
||
{
|
||
// 在实际测试中,可以使用更高级的模拟技术
|
||
// 这里仅提供基础框架
|
||
}
|
||
|
||
/**
|
||
* 断言相等
|
||
*/
|
||
private function assertEquals($expected, $actual, $message = '')
|
||
{
|
||
if ($expected !== $actual) {
|
||
throw new \Exception($message ?: "断言失败: 期望 {$expected},实际得到 {$actual}");
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果直接运行此文件,则执行测试
|
||
if (basename(__FILE__) == basename($_SERVER['PHP_SELF'])) {
|
||
$test = new HuaweiPayClientTest();
|
||
$test->runTests();
|
||
} |