service = new CouponService(); // 清理测试数据 DB::connection('write')->table(UserCoupon::TABLE) ->where('user_id', $this->testUserId) ->delete(); } public function tearDown(): void { // 清理测试数据 DB::connection('write')->table(UserCoupon::TABLE) ->where('user_id', $this->testUserId) ->delete(); parent::tearDown(); } // ======================== // 固定金额券 - 金币计算 // ======================== /** * 测试固定金额券:赠送金额等于券面值 */ public function test_calc_bonus_coins_fixed_type() { $coupon = (object) [ 'coupon_type' => UserCoupon::TYPE_FIXED, 'coupon_value' => 10.00, // 10元 'max_bonus' => 0, ]; $bonus = $this->service->calcBonusCoins($coupon, 50.00); $this->assertEquals(1000, $bonus); // 10元 × 100 = 1000分 } /** * 测试固定金额券:不同充值金额,赠送不变 */ public function test_calc_bonus_coins_fixed_independent_of_pay_amt() { $coupon = (object) [ 'coupon_type' => UserCoupon::TYPE_FIXED, 'coupon_value' => 5.00, 'max_bonus' => 0, ]; $bonus1 = $this->service->calcBonusCoins($coupon, 10.00); $bonus2 = $this->service->calcBonusCoins($coupon, 100.00); $this->assertEquals($bonus1, $bonus2); // 固定金额与充值额无关 $this->assertEquals(500, $bonus1); } // ======================== // 百分比券 - 金币计算 // ======================== /** * 测试百分比券:按充值金额百分比计算 */ public function test_calc_bonus_coins_percent_type() { $coupon = (object) [ 'coupon_type' => UserCoupon::TYPE_PERCENT, 'coupon_value' => 50, // 50% 'max_bonus' => 100, // 上限100元 ]; $bonus = $this->service->calcBonusCoins($coupon, 40.00); $this->assertEquals(2000, $bonus); // 40 × 50% × 100 = 2000分 } /** * 测试百分比券:超过上限时按上限计算 */ public function test_calc_bonus_coins_percent_capped_at_max() { $coupon = (object) [ 'coupon_type' => UserCoupon::TYPE_PERCENT, 'coupon_value' => 50, 'max_bonus' => 30, // 上限30元 ]; // 充值200元,50% = 100元,但上限30元 → 3000分 $bonus = $this->service->calcBonusCoins($coupon, 200.00); $this->assertEquals(3000, $bonus); // 30 × 100 = 3000分 } // ======================== // 优惠券验证 // ======================== /** * 测试验证:优惠券不存在 */ public function test_validate_coupon_not_found() { $result = $this->service->validateCoupon(99999, $this->testUserId, 50.00); $this->assertFalse($result['valid']); $this->assertEquals('Coupon not found', $result['error']); } /** * 测试验证:充值金额不满足最低门槛 */ public function test_validate_coupon_below_min_recharge() { // 手动插入一张测试券 $couponId = DB::connection('write')->table(UserCoupon::TABLE)->insertGetId([ 'user_id' => $this->testUserId, 'coupon_name' => 'test_fixed', 'coupon_type' => UserCoupon::TYPE_FIXED, 'coupon_value' => 10.00, 'min_recharge' => 50.00, // 最低50元 'max_bonus' => 0, 'bonus_coins' => 0, 'order_sn' => '', 'status' => UserCoupon::STATUS_UNUSED, 'issued_at' => date('Y-m-d H:i:s'), 'used_at' => null, 'expire_at' => date('Y-m-d H:i:s', strtotime('+7 days')), ]); $result = $this->service->validateCoupon($couponId, $this->testUserId, 20.00); // 20 < 50 $this->assertFalse($result['valid']); $this->assertStringContainsString('Minimum recharge', $result['error']); } /** * 测试验证:优惠券已过期 */ public function test_validate_coupon_expired() { $couponId = DB::connection('write')->table(UserCoupon::TABLE)->insertGetId([ 'user_id' => $this->testUserId, 'coupon_name' => 'test_expired', 'coupon_type' => UserCoupon::TYPE_FIXED, 'coupon_value' => 10.00, 'min_recharge' => 0, 'max_bonus' => 0, 'bonus_coins' => 0, 'order_sn' => '', 'status' => UserCoupon::STATUS_UNUSED, 'issued_at' => date('Y-m-d H:i:s', strtotime('-10 days')), 'used_at' => null, 'expire_at' => date('Y-m-d H:i:s', strtotime('-1 day')), // 已过期 ]); $result = $this->service->validateCoupon($couponId, $this->testUserId, 50.00); $this->assertFalse($result['valid']); $this->assertEquals('Coupon expired', $result['error']); } /** * 测试验证:有效优惠券 */ public function test_validate_coupon_valid() { $couponId = DB::connection('write')->table(UserCoupon::TABLE)->insertGetId([ 'user_id' => $this->testUserId, 'coupon_name' => 'test_valid', 'coupon_type' => UserCoupon::TYPE_FIXED, 'coupon_value' => 10.00, 'min_recharge' => 30.00, 'max_bonus' => 0, 'bonus_coins' => 0, 'order_sn' => '', 'status' => UserCoupon::STATUS_UNUSED, 'issued_at' => date('Y-m-d H:i:s'), 'used_at' => null, 'expire_at' => date('Y-m-d H:i:s', strtotime('+7 days')), ]); $result = $this->service->validateCoupon($couponId, $this->testUserId, 50.00); $this->assertTrue($result['valid']); } // ======================== // 防重复发放 // ======================== /** * 测试 hasSameCoupon:有效券存在时返回 true */ public function test_has_same_coupon_returns_true_when_valid_exists() { $couponName = 'test_duplicate_check'; DB::connection('write')->table(UserCoupon::TABLE)->insert([ 'user_id' => $this->testUserId, 'coupon_name' => $couponName, 'coupon_type' => UserCoupon::TYPE_FIXED, 'coupon_value' => 5.00, 'min_recharge' => 0, 'max_bonus' => 0, 'bonus_coins' => 0, 'order_sn' => '', 'status' => UserCoupon::STATUS_UNUSED, 'issued_at' => date('Y-m-d H:i:s'), 'used_at' => null, 'expire_at' => date('Y-m-d H:i:s', strtotime('+7 days')), ]); $this->assertTrue(UserCoupon::hasSameCoupon($this->testUserId, $couponName)); } /** * 测试 hasSameCoupon:同名券已过期时返回 false(允许重新发放) */ public function test_has_same_coupon_returns_false_when_expired() { $couponName = 'test_expired_dup'; DB::connection('write')->table(UserCoupon::TABLE)->insert([ 'user_id' => $this->testUserId, 'coupon_name' => $couponName, 'coupon_type' => UserCoupon::TYPE_FIXED, 'coupon_value' => 5.00, 'min_recharge' => 0, 'max_bonus' => 0, 'bonus_coins' => 0, 'order_sn' => '', 'status' => UserCoupon::STATUS_UNUSED, 'issued_at' => date('Y-m-d H:i:s', strtotime('-10 days')), 'used_at' => null, 'expire_at' => date('Y-m-d H:i:s', strtotime('-1 day')), // 已过期 ]); $this->assertFalse(UserCoupon::hasSameCoupon($this->testUserId, $couponName)); } }