$userId, 'item_id' => $itemId, 'instance_id' => null, 'quantity' => $originalQuantity, 'expire_at' => now()->addDays(30), 'is_frozen' => false, 'frozen_log_id' => null, ]); // 执行部分冻结操作(会触发拆堆) $result = ItemFreeze::freezeNormalItem( $userId, $itemId, $freezeQuantity, FREEZE_REASON_TYPE::TRADE_ORDER, 12345, 'test_order', null ); // 验证冻结操作成功 $this->assertTrue($result['success']); $this->assertEquals($freezeQuantity, $result['frozen_quantity']); // 验证触发了两个事件 Event::assertDispatchedTimes(ItemQuantityChanged::class, 2); // 验证第一个事件:原堆叠数量减少 Event::assertDispatched(ItemQuantityChanged::class, function ($event) use ($userId, $itemId, $userItem, $originalQuantity, $freezeQuantity) { return $event->userId === $userId && $event->itemId === $itemId && $event->userItemId === $userItem->id && $event->oldQuantity === $originalQuantity && $event->newQuantity === ($originalQuantity - $freezeQuantity) && $event->changeAmount === -$freezeQuantity && $event->oldFrozenStatus === false && $event->newFrozenStatus === false // 冻结状态不变 && isset($event->options['change_type']) && $event->options['change_type'] === 'quantity_decrease'; }); // 验证第二个事件:新冻结堆叠创建 Event::assertDispatched(ItemQuantityChanged::class, function ($event) use ($userId, $itemId, $freezeQuantity) { return $event->userId === $userId && $event->itemId === $itemId && $event->userItemId !== null // 新创建的堆叠ID && $event->oldQuantity === 0 && $event->newQuantity === $freezeQuantity && $event->changeAmount === $freezeQuantity && $event->oldFrozenStatus === null // 新创建的物品 && $event->newFrozenStatus === true && isset($event->options['change_type']) && $event->options['change_type'] === 'frozen_item_create'; }); // 手动触发事件处理(因为使用了Event::fake) $events = Event::dispatched(ItemQuantityChanged::class); foreach ($events as $eventData) { $event = $eventData[0]; // 获取事件实例 ItemTemp::handleItemQuantityChanged($event); } // 验证临时数据中包含两个物品堆的变更信息 $itemChanges = ItemTemp::getUserItemChanges($userId); $this->assertCount(2, $itemChanges, '应该有两个物品堆的变更记录'); // 验证原堆叠的变更记录 $originalStackChange = null; $frozenStackChange = null; foreach ($itemChanges as $change) { if ($change->userItemId === $userItem->id) { $originalStackChange = $change; } else { $frozenStackChange = $change; } } $this->assertNotNull($originalStackChange, '应该有原堆叠的变更记录'); $this->assertNotNull($frozenStackChange, '应该有冻结堆叠的变更记录'); // 验证原堆叠变更记录的正确性 $this->assertEquals($itemId, $originalStackChange->itemId); $this->assertEquals($originalQuantity, $originalStackChange->oldQuantity); $this->assertEquals($originalQuantity - $freezeQuantity, $originalStackChange->newQuantity); $this->assertEquals(-$freezeQuantity, $originalStackChange->changeAmount); $this->assertFalse($originalStackChange->oldFrozenStatus); $this->assertFalse($originalStackChange->newFrozenStatus); // 验证冻结堆叠变更记录的正确性 $this->assertEquals($itemId, $frozenStackChange->itemId); $this->assertEquals(0, $frozenStackChange->oldQuantity); $this->assertEquals($freezeQuantity, $frozenStackChange->newQuantity); $this->assertEquals($freezeQuantity, $frozenStackChange->changeAmount); $this->assertNull($frozenStackChange->oldFrozenStatus); $this->assertTrue($frozenStackChange->newFrozenStatus); } finally { DB::rollBack(); } } /** * 测试全部冻结时的单事件触发和同步 * * 验证当物品全部冻结不需要拆堆时,只触发一个冻结状态变更事件 */ public function test_full_freeze_single_event_sync() { DB::beginTransaction(); try { $userId = 1002; $itemId = 3; // 使用现有的辣椒物品 $quantity = 50; // 清理可能存在的临时数据 ItemTemp::clearUserItemChanges($userId); // 创建测试用户物品记录 $userItem = ItemUser::create([ 'user_id' => $userId, 'item_id' => $itemId, 'instance_id' => null, 'quantity' => $quantity, 'expire_at' => now()->addDays(30), 'is_frozen' => false, 'frozen_log_id' => null, ]); // 执行全部冻结操作(不会拆堆) $result = ItemFreeze::freezeNormalItem( $userId, $itemId, $quantity, // 全部冻结 FREEZE_REASON_TYPE::TRADE_ORDER, 12346, 'test_order', null ); // 验证冻结操作成功 $this->assertTrue($result['success']); $this->assertEquals($quantity, $result['frozen_quantity']); // 验证只触发了一个事件 Event::assertDispatchedTimes(ItemQuantityChanged::class, 1); // 验证事件:冻结状态变更 Event::assertDispatched(ItemQuantityChanged::class, function ($event) use ($userId, $itemId, $userItem, $quantity) { return $event->userId === $userId && $event->itemId === $itemId && $event->userItemId === $userItem->id && $event->oldQuantity === $quantity && $event->newQuantity === $quantity // 数量不变 && $event->changeAmount === 0 && $event->oldFrozenStatus === false && $event->newFrozenStatus === true && isset($event->options['change_type']) && $event->options['change_type'] === 'freeze_status_change'; }); // 手动触发事件处理 $events = Event::dispatched(ItemQuantityChanged::class); foreach ($events as $eventData) { $event = $eventData[0]; ItemTemp::handleItemQuantityChanged($event); } // 验证临时数据中只有一个物品堆的变更信息 $itemChanges = ItemTemp::getUserItemChanges($userId); $this->assertCount(1, $itemChanges, '应该只有一个物品堆的变更记录'); $change = $itemChanges[0]; $this->assertEquals($userItem->id, $change->userItemId); $this->assertEquals($itemId, $change->itemId); $this->assertEquals($quantity, $change->oldQuantity); $this->assertEquals($quantity, $change->newQuantity); $this->assertEquals(0, $change->changeAmount); $this->assertFalse($change->oldFrozenStatus); $this->assertTrue($change->newFrozenStatus); } finally { DB::rollBack(); } } }