'fishing'], [ 'name' => 'Fishing', 'icon' => 'fish', 'description' => 'Fishing Game', 'enabled' => true, 'params' => [ 'fishing_cost' => 5, 'fishing_cooldown' => 300, ], ] ); } /** * 方法功能:验证用户金币足够时可以正常抛竿并扣除费用。 */ public function test_can_cast_rod(): void { /** @var \App\Models\User $user */ $user = User::factory()->create(['jjb' => 10]); $response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1])); $response->assertStatus(200); $response->assertJson([ 'status' => 'success', 'cost' => 5, ]); $this->assertEquals(5, $user->fresh()->jjb); } /** * 方法功能:验证冷却期间不能重复抛竿。 */ public function test_cannot_cast_when_on_cooldown(): void { /** @var \App\Models\User $user */ $user = User::factory()->create(['jjb' => 10]); Redis::setex("fishing:cd:{$user->id}", 100, time()); $response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1])); $response->assertStatus(429); $response->assertJson([ 'status' => 'error', ]); } /** * 方法功能:验证金币不足时不能抛竿。 */ public function test_cannot_cast_without_enough_gold(): void { /** @var \App\Models\User $user */ $user = User::factory()->create(['jjb' => 2]); $response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1])); $response->assertStatus(422); $response->assertJson([ 'status' => 'error', ]); } /** * 方法功能:验证等待完成后携带正确令牌可以成功收竿。 */ public function test_can_reel_after_waiting(): void { /** @var \App\Models\User $user */ $user = User::factory()->create(['jjb' => 10]); $token = 'test-token'; Redis::set("fishing:token:{$user->id}", json_encode([ 'token' => $token, 'cast_at' => time() - 1, // Simulate past 'wait_time' => 0, ])); $response = $this->actingAs($user)->postJson(route('fishing.reel', ['id' => 1]), [ 'token' => $token, ]); $response->assertStatus(200); $response->assertJson([ 'status' => 'success', ]); // Cooldown should be set $this->assertTrue((bool) Redis::exists("fishing:cd:{$user->id}")); } /** * 方法功能:验证错误令牌不能收竿。 */ public function test_cannot_reel_with_invalid_token(): void { /** @var \App\Models\User $user */ $user = User::factory()->create(['jjb' => 10]); Redis::set("fishing:token:{$user->id}", json_encode([ 'token' => 'valid-token', 'cast_at' => time(), 'wait_time' => 0, ])); $response = $this->actingAs($user)->postJson(route('fishing.reel', ['id' => 1]), [ 'token' => 'invalid-token', ]); $response->assertStatus(422); $response->assertJson([ 'status' => 'error', ]); } /** * 方法功能:验证已有未收竿令牌时再次抛竿会恢复原会话且不会重复扣金币。 */ public function test_cast_restores_active_token_without_charging_again(): void { /** @var \App\Models\User $user */ $user = User::factory()->create(['jjb' => 10]); $tokenKey = "fishing:token:{$user->id}"; $payload = json_encode([ 'token' => 'active-token', 'cast_at' => time(), 'wait_time' => 10, ]); Redis::setex($tokenKey, 20, $payload); $response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1])); $response->assertStatus(200); $response->assertJson([ 'status' => 'success', 'token' => 'active-token', 'cost' => 0, 'restored' => true, ]); $this->assertSame(10, $user->fresh()->jjb); $this->assertSame($payload, Redis::get($tokenKey)); } }