| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- <?php
- namespace Tests\Unit\Transfer;
- use Tests\TestCase;
- use App\Module\Transfer\Logics\TransferLogic;
- use App\Module\Transfer\Models\TransferApp;
- use App\Module\Fund\Services\FundService;
- use App\Module\Fund\Logic\User as FundUser;
- use Illuminate\Foundation\Testing\RefreshDatabase;
- use Illuminate\Support\Facades\DB;
- /**
- * 划转余额验证测试
- *
- * 测试修复后的余额验证机制,确保不会再出现超额扣除问题
- */
- class TransferBalanceValidationTest extends TestCase
- {
- use RefreshDatabase;
- private $testUserId = 99999;
- private $testFundId = 2;
- private $testTransferAppId;
- protected function setUp(): void
- {
- parent::setUp();
-
- // 创建测试用的转账应用
- $this->testTransferAppId = $this->createTestTransferApp();
-
- // 创建测试用户的资金账户
- $this->createTestUserFund();
- }
- /**
- * 测试Fund模块余额验证机制
- * 验证修复后不会允许余额变成负数
- */
- public function testFundBalanceValidationPreventsNegativeBalance()
- {
- // 设置用户余额为1000
- $this->setUserBalance(1000);
-
- // 尝试扣除超额金额(2000)
- $result = FundUser::handle(
- $this->testUserId,
- $this->testFundId,
- -2000, // 扣除2000,但用户只有1000
- \App\Module\Fund\Enums\LOG_TYPE::TRADE,
- 'test-insufficient-funds',
- '测试余额不足'
- );
-
- // 应该返回错误信息
- $this->assertIsString($result);
- $this->assertStringContains('not-sufficient-funds', $result);
-
- // 验证用户余额没有被修改
- $fundService = new FundService($this->testUserId, $this->testFundId);
- $this->assertEquals(1000, $fundService->balance());
- }
- /**
- * 测试Transfer模块预先余额验证
- * 验证转出前会检查余额是否充足
- */
- public function testTransferPreBalanceValidation()
- {
- // 设置用户余额为500
- $this->setUserBalance(500);
-
- // 尝试转出超额金额(1000)
- $this->expectException(\Exception::class);
- $this->expectExceptionMessage('用户余额不足');
-
- TransferLogic::createTransferOutForThirdParty(
- $this->testTransferAppId,
- $this->testUserId,
- '1000', // 转出1000,但用户只有500
- null,
- '测试超额转出',
- []
- );
- }
- /**
- * 测试异常金额预警机制
- * 验证超大金额会被拒绝
- */
- public function testAbnormalAmountValidation()
- {
- // 设置用户余额为足够大的金额
- $this->setUserBalance(100000000);
-
- // 尝试转出异常大金额(超过1000万限制)
- $this->expectException(\Exception::class);
-
- TransferLogic::createTransferOutForThirdParty(
- $this->testTransferAppId,
- $this->testUserId,
- '20000000', // 2000万,超过1000万限制
- null,
- '测试异常大金额',
- []
- );
- }
- /**
- * 测试汇率验证机制
- * 验证汇率配置错误时会被拒绝
- */
- public function testExchangeRateValidation()
- {
- // 设置用户余额
- $this->setUserBalance(1000);
-
- // 修改转账应用的汇率为0(异常值)
- $app = TransferApp::find($this->testTransferAppId);
- $app->exchange_rate = 0;
- $app->save();
-
- // 尝试转出
- $this->expectException(\Exception::class);
- $this->expectExceptionMessage('汇率配置错误:汇率必须大于0');
-
- TransferLogic::createTransferOutForThirdParty(
- $this->testTransferAppId,
- $this->testUserId,
- '100',
- null,
- '测试汇率错误',
- []
- );
- }
- /**
- * 测试正常转出流程
- * 验证修复后正常转出仍然可以工作
- */
- public function testNormalTransferStillWorks()
- {
- // 设置用户余额为1000
- $this->setUserBalance(1000);
-
- // 正常转出100
- $order = TransferLogic::createTransferOutForThirdParty(
- $this->testTransferAppId,
- $this->testUserId,
- '100',
- null,
- '测试正常转出',
- []
- );
-
- // 验证订单创建成功
- $this->assertNotNull($order);
- $this->assertEquals('100', $order->amount);
-
- // 验证用户余额正确扣除(100 + 手续费)
- $fundService = new FundService($this->testUserId, $this->testFundId);
- $expectedBalance = 1000 - 100 - $order->fee_amount;
- $this->assertEquals($expectedBalance, $fundService->balance());
- }
- /**
- * 创建测试用的转账应用
- */
- private function createTestTransferApp(): int
- {
- return DB::table('kku_transfer_apps')->insertGetId([
- 'keyname' => 'test_app',
- 'title' => '测试应用',
- 'description' => '测试用转账应用',
- 'out_id2' => 1,
- 'out_id3' => 11,
- 'currency_id' => 2,
- 'fund_id' => $this->testFundId,
- 'fund_to_uid' => 1,
- 'fund_in_uid' => 1,
- 'exchange_rate' => '300.0000',
- 'is_enabled' => 1,
- 'allow_transfer_in' => 1,
- 'allow_transfer_out' => 1,
- 'fee_in_rate' => '0.0050',
- 'fee_out_rate' => '0.0100',
- 'fee_in_min' => '0.3000',
- 'fee_in_max' => '5.0000',
- 'fee_out_min' => '0.5000',
- 'fee_out_max' => '10.0000',
- 'fee_account_uid' => 1,
- 'created_at' => now(),
- 'updated_at' => now(),
- ]);
- }
- /**
- * 创建测试用户的资金账户
- */
- private function createTestUserFund(): void
- {
- DB::table('kku_fund')->insert([
- 'user_id' => $this->testUserId,
- 'fund_id' => $this->testFundId,
- 'balance' => '0.0000000000',
- 'create_time' => time(),
- 'update_time' => time(),
- ]);
- }
- /**
- * 设置用户余额
- */
- private function setUserBalance(float $balance): void
- {
- DB::table('kku_fund')
- ->where('user_id', $this->testUserId)
- ->where('fund_id', $this->testFundId)
- ->update([
- 'balance' => number_format($balance, 10, '.', ''),
- 'update_time' => time(),
- ]);
- }
- }
|