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(), ]); } }