ItemFreezeLastDataSyncTest.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <?php
  2. namespace Tests\Unit\GameItems;
  3. use App\Module\Game\Logics\ItemTemp;
  4. use App\Module\GameItems\Enums\FREEZE_REASON_TYPE;
  5. use App\Module\GameItems\Events\ItemQuantityChanged;
  6. use App\Module\GameItems\Logics\ItemFreeze;
  7. use App\Module\GameItems\Models\ItemFreezeLog;
  8. use App\Module\GameItems\Models\ItemUser;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Event;
  11. use Tests\TestCase;
  12. /**
  13. * 物品冻结lastdata同步测试
  14. *
  15. * 测试物品冻结功能的lastdata同步问题修复
  16. */
  17. class ItemFreezeLastDataSyncTest extends TestCase
  18. {
  19. protected function setUp(): void
  20. {
  21. parent::setUp();
  22. // 启用事件监听
  23. Event::fake([ItemQuantityChanged::class]);
  24. }
  25. /**
  26. * 测试部分冻结时的事件触发
  27. *
  28. * 验证当进行部分冻结(拆堆)时:
  29. * 1. 原堆叠数量减少事件被正确触发
  30. * 2. 新冻结堆叠创建事件被正确触发
  31. */
  32. public function test_partial_freeze_triggers_correct_events()
  33. {
  34. DB::beginTransaction();
  35. try {
  36. $userId = 1001;
  37. $itemId = 2001;
  38. $originalQuantity = 100;
  39. $freezeQuantity = 30;
  40. // 创建用户物品记录
  41. $userItem = ItemUser::create([
  42. 'user_id' => $userId,
  43. 'item_id' => $itemId,
  44. 'instance_id' => null,
  45. 'quantity' => $originalQuantity,
  46. 'expire_at' => now()->addDays(30),
  47. 'is_frozen' => false,
  48. 'frozen_log_id' => null,
  49. ]);
  50. // 执行部分冻结操作
  51. $result = ItemFreeze::freezeNormalItem(
  52. $userId,
  53. $itemId,
  54. $freezeQuantity,
  55. FREEZE_REASON_TYPE::TRADE_ORDER,
  56. 12345,
  57. 'order',
  58. null
  59. );
  60. // 验证冻结操作成功
  61. $this->assertTrue($result['success']);
  62. $this->assertEquals($freezeQuantity, $result['frozen_quantity']);
  63. // 验证数据库状态
  64. // 原堆叠数量应该减少
  65. $userItem->refresh();
  66. $this->assertEquals($originalQuantity - $freezeQuantity, $userItem->quantity);
  67. $this->assertFalse($userItem->is_frozen);
  68. // 应该创建新的冻结堆叠
  69. $frozenItem = ItemUser::where('user_id', $userId)
  70. ->where('item_id', $itemId)
  71. ->where('is_frozen', true)
  72. ->first();
  73. $this->assertNotNull($frozenItem);
  74. $this->assertEquals($freezeQuantity, $frozenItem->quantity);
  75. // 验证事件触发
  76. Event::assertDispatched(ItemQuantityChanged::class, 2); // 应该触发2个事件
  77. // 验证第一个事件:原堆叠数量减少
  78. Event::assertDispatched(ItemQuantityChanged::class, function ($event) use ($userId, $itemId, $userItem, $originalQuantity, $freezeQuantity) {
  79. return $event->userId === $userId
  80. && $event->itemId === $itemId
  81. && $event->userItemId === $userItem->id
  82. && $event->oldQuantity === $originalQuantity
  83. && $event->newQuantity === ($originalQuantity - $freezeQuantity)
  84. && $event->oldFrozenStatus === false
  85. && $event->newFrozenStatus === false
  86. && isset($event->options['change_type'])
  87. && $event->options['change_type'] === 'quantity_decrease';
  88. });
  89. // 验证第二个事件:新冻结堆叠创建
  90. Event::assertDispatched(ItemQuantityChanged::class, function ($event) use ($userId, $itemId, $freezeQuantity) {
  91. return $event->userId === $userId
  92. && $event->itemId === $itemId
  93. && $event->oldQuantity === 0 // 新创建的物品,旧数量为0
  94. && $event->newQuantity === $freezeQuantity
  95. && $event->oldFrozenStatus === null // 新创建的物品,旧冻结状态为null
  96. && $event->newFrozenStatus === true
  97. && isset($event->options['change_type'])
  98. && $event->options['change_type'] === 'frozen_item_create';
  99. });
  100. } finally {
  101. DB::rollBack();
  102. }
  103. }
  104. /**
  105. * 测试全部冻结时的事件触发
  106. *
  107. * 验证当进行全部冻结时:
  108. * 只触发冻结状态变更事件,不涉及数量变更
  109. */
  110. public function test_full_freeze_triggers_correct_event()
  111. {
  112. DB::beginTransaction();
  113. try {
  114. $userId = 1002;
  115. $itemId = 2002;
  116. $quantity = 50;
  117. // 创建用户物品记录
  118. $userItem = ItemUser::create([
  119. 'user_id' => $userId,
  120. 'item_id' => $itemId,
  121. 'instance_id' => null,
  122. 'quantity' => $quantity,
  123. 'expire_at' => now()->addDays(30),
  124. 'is_frozen' => false,
  125. 'frozen_log_id' => null,
  126. ]);
  127. // 执行全部冻结操作
  128. $result = ItemFreeze::freezeNormalItem(
  129. $userId,
  130. $itemId,
  131. $quantity, // 冻结全部数量
  132. FREEZE_REASON_TYPE::ADMIN_FREEZE,
  133. null,
  134. null,
  135. 1
  136. );
  137. // 验证冻结操作成功
  138. $this->assertTrue($result['success']);
  139. $this->assertEquals($quantity, $result['frozen_quantity']);
  140. // 验证数据库状态
  141. $userItem->refresh();
  142. $this->assertEquals($quantity, $userItem->quantity); // 数量不变
  143. $this->assertTrue($userItem->is_frozen); // 冻结状态变为true
  144. // 验证事件触发
  145. Event::assertDispatched(ItemQuantityChanged::class, 1); // 应该只触发1个事件
  146. // 验证事件:冻结状态变更
  147. Event::assertDispatched(ItemQuantityChanged::class, function ($event) use ($userId, $itemId, $userItem, $quantity) {
  148. return $event->userId === $userId
  149. && $event->itemId === $itemId
  150. && $event->userItemId === $userItem->id
  151. && $event->oldQuantity === $quantity
  152. && $event->newQuantity === $quantity // 数量不变
  153. && $event->oldFrozenStatus === false
  154. && $event->newFrozenStatus === true
  155. && isset($event->options['change_type'])
  156. && $event->options['change_type'] === 'freeze_status_change';
  157. });
  158. } finally {
  159. DB::rollBack();
  160. }
  161. }
  162. /**
  163. * 测试lastdata同步数据的正确性
  164. *
  165. * 验证事件触发后,临时数据是否正确存储
  166. */
  167. public function test_lastdata_sync_data_correctness()
  168. {
  169. DB::beginTransaction();
  170. try {
  171. $userId = 1003;
  172. $itemId = 2003;
  173. $originalQuantity = 80;
  174. $freezeQuantity = 25;
  175. // 创建用户物品记录
  176. $userItem = ItemUser::create([
  177. 'user_id' => $userId,
  178. 'item_id' => $itemId,
  179. 'instance_id' => null,
  180. 'quantity' => $originalQuantity,
  181. 'expire_at' => now()->addDays(30),
  182. 'is_frozen' => false,
  183. 'frozen_log_id' => null,
  184. ]);
  185. // 清空事件fake,使用真实的事件监听器
  186. Event::fake([]); // 清空fake
  187. // 执行部分冻结操作
  188. ItemFreeze::freezeNormalItem(
  189. $userId,
  190. $itemId,
  191. $freezeQuantity,
  192. FREEZE_REASON_TYPE::SYSTEM_FREEZE,
  193. null,
  194. null,
  195. null
  196. );
  197. // 获取临时数据
  198. $tempData = ItemTemp::getUserItemChanges($userId);
  199. // 验证临时数据包含了物品变更信息
  200. $this->assertNotEmpty($tempData);
  201. $this->assertArrayHasKey($itemId, $tempData);
  202. $itemChange = $tempData[$itemId];
  203. // 验证临时数据的正确性
  204. // 注意:由于同一物品的多次变更会覆盖,这里应该是最后一次变更(冻结堆叠创建)的数据
  205. $this->assertEquals($itemId, $itemChange->itemId);
  206. $this->assertEquals($freezeQuantity, $itemChange->newQuantity);
  207. $this->assertTrue($itemChange->newFrozenStatus);
  208. } finally {
  209. DB::rollBack();
  210. }
  211. }
  212. }