handle(); $this->assertTrue(true); } /** @test */ public function test_skips_when_ip_is_empty() { $job = new IpRiskDetection(12345, ''); $job->handle(); $this->assertTrue(true); } /** @test */ public function test_skips_when_both_are_empty() { $job = new IpRiskDetection(0, ''); $job->handle(); $this->assertTrue(true); } // ==================== 重复检测跳过 ==================== /** @test */ public function test_skips_detection_when_same_ip_in_today_hash() { $userId = 10001; $ip = '73.162.0.1'; $todayKey = IpRiskDetection::LAST_DETECTED_PREFIX . date('Ymd'); Redis::shouldReceive('hget') ->once() ->with($todayKey, $userId) ->andReturn($ip); $job = new IpRiskDetection($userId, $ip); $job->handle(); $this->assertTrue(true); } /** @test */ public function test_skips_detection_when_same_ip_in_yesterday_hash() { $userId = 10001; $ip = '73.162.0.1'; $todayKey = IpRiskDetection::LAST_DETECTED_PREFIX . date('Ymd'); $yesterdayKey = IpRiskDetection::LAST_DETECTED_PREFIX . date('Ymd', strtotime('-1 day')); // today miss → yesterday hit Redis::shouldReceive('hget') ->once() ->with($todayKey, $userId) ->andReturn(null); Redis::shouldReceive('hget') ->once() ->with($yesterdayKey, $userId) ->andReturn($ip); $job = new IpRiskDetection($userId, $ip); $job->handle(); $this->assertTrue(true); } // ==================== 容器内集成测试 ==================== /** * 以下测试需要模拟 IpRiskService,但 Job 内部通过 new 创建服务实例。 * * 测试策略: * - IpRiskService 自身的 detect() 逻辑已在 IpRiskServiceTest 中覆盖 * - Job 与 Redis 的交互在上述测试中覆盖 * - 完整链路测试建议在验收环境中通过实际登录/注册流程验证 */ /** @test */ public function test_has_correct_constants() { $this->assertEquals('ip_risk_users', IpRiskDetection::REDIS_HASH_KEY); $this->assertEquals('ip_risk_last_detected:', IpRiskDetection::LAST_DETECTED_PREFIX); $this->assertEquals(3, IpRiskDetection::DETECTION_WINDOW_DAYS); } /** @test */ public function test_implements_should_queue() { $job = new IpRiskDetection(1, '1.2.3.4'); $this->assertInstanceOf(\Illuminate\Contracts\Queue\ShouldQueue::class, $job); } }