using FsCheck; using FsCheck.Xunit; using Xunit; using XiangYi.Application.Services; using XiangYi.Core.Entities.Biz; namespace XiangYi.Application.Tests.Services; /// /// RecommendService属性测试 - 推荐数量与会员等级 /// public class RecommendCountPropertyTests { /// /// **Feature: backend-api, Property 5: 推荐数量与会员等级关联** /// **Validates: Requirements 3.1, 7.4** /// /// *For any* 用户请求推荐列表, 普通用户返回不超过10人,不限时会员返回24人,诚意会员返回24-29人 /// [Property(MaxTest = 100)] public Property RecommendCount_ShouldMatchMemberLevel() { // 生成有效的会员等级(0-4) var memberLevelArb = Gen.Choose(0, 4); return Prop.ForAll( memberLevelArb.ToArbitrary(), memberLevel => { // Act var (minCount, maxCount) = RecommendService.GetRecommendCountRangeByMemberLevel(memberLevel); var actualCount = RecommendService.GetRecommendCountByMemberLevelStatic(memberLevel); // Assert return memberLevel switch { // 普通用户:恰好4人 0 => actualCount == RecommendService.NormalUserRecommendCount && minCount == 4 && maxCount == 4, // 不限时会员:恰好24人 1 => actualCount == RecommendService.UnlimitedMemberRecommendCount && minCount == 24 && maxCount == 24, // 诚意会员:24-29人 2 => actualCount >= RecommendService.SincereMemberMinRecommendCount && actualCount <= RecommendService.SincereMemberMaxRecommendCount && minCount == 24 && maxCount == 29, // 家庭版会员:24-29人 3 => actualCount >= RecommendService.SincereMemberMinRecommendCount && actualCount <= RecommendService.SincereMemberMaxRecommendCount && minCount == 24 && maxCount == 29, // 限时会员:恰好24人 4 => actualCount == RecommendService.UnlimitedMemberRecommendCount && minCount == 24 && maxCount == 24, _ => false }; }); } /// /// 普通用户推荐数量应为4 /// [Property(MaxTest = 100)] public Property NormalUser_ShouldGet10Recommendations() { return Prop.ForAll( Arb.Default.PositiveInt(), _ => { var count = RecommendService.GetRecommendCountByMemberLevelStatic(0); return count == 4; }); } /// /// 不限时会员推荐数量应为24 /// [Property(MaxTest = 100)] public Property UnlimitedMember_ShouldGet24Recommendations() { return Prop.ForAll( Arb.Default.PositiveInt(), _ => { var count = RecommendService.GetRecommendCountByMemberLevelStatic(1); return count == 24; }); } /// /// 诚意会员推荐数量应在24-29之间 /// [Property(MaxTest = 100)] public Property SincereMember_ShouldGet24To29Recommendations() { return Prop.ForAll( Arb.Default.PositiveInt(), _ => { var count = RecommendService.GetRecommendCountByMemberLevelStatic(2); return count >= 24 && count <= 29; }); } /// /// 家庭版会员推荐数量应在24-29之间 /// [Property(MaxTest = 100)] public Property FamilyMember_ShouldGet24Recommendations() { return Prop.ForAll( Arb.Default.PositiveInt(), _ => { var count = RecommendService.GetRecommendCountByMemberLevelStatic(3); return count >= 24 && count <= 29; }); } /// /// 无效会员等级应返回普通用户数量 /// [Property(MaxTest = 100)] public Property InvalidMemberLevel_ShouldReturnNormalUserCount() { // 生成无效的会员等级(负数或大于4) var invalidLevelArb = Gen.OneOf( Gen.Choose(-100, -1), Gen.Choose(5, 100) ); return Prop.ForAll( invalidLevelArb.ToArbitrary(), invalidLevel => { var count = RecommendService.GetRecommendCountByMemberLevelStatic(invalidLevel); return count == RecommendService.NormalUserRecommendCount; }); } /// /// 会员推荐数量应大于等于普通用户 /// [Property(MaxTest = 100)] public Property MemberRecommendCount_ShouldBeGreaterOrEqualToNormalUser() { var memberLevelArb = Gen.Choose(1, 4); // 会员等级1-4 return Prop.ForAll( memberLevelArb.ToArbitrary(), memberLevel => { var memberCount = RecommendService.GetRecommendCountByMemberLevelStatic(memberLevel); var normalCount = RecommendService.GetRecommendCountByMemberLevelStatic(0); return memberCount >= normalCount; }); } /// /// 常量值验证 /// [Fact] public void Constants_ShouldHaveCorrectValues() { Assert.Equal(4, RecommendService.NormalUserRecommendCount); Assert.Equal(24, RecommendService.UnlimitedMemberRecommendCount); Assert.Equal(24, RecommendService.SincereMemberMinRecommendCount); Assert.Equal(29, RecommendService.SincereMemberMaxRecommendCount); Assert.Equal(24, RecommendService.FamilyMemberRecommendCount); Assert.Equal(3, RecommendService.DeduplicationDays); Assert.Equal(30, RecommendService.NewUserPriorityMinutes); } } /// /// RecommendService属性测试 - 推荐去重规则 /// public class RecommendDeduplicationPropertyTests { /// /// **Feature: backend-api, Property 6: 推荐去重规则** /// **Validates: Requirements 3.3** /// /// *For any* 生成的推荐列表, 3天内已推荐过的用户不应再次出现(用户数量充足时) /// [Property(MaxTest = 100)] public Property RecommendDeduplication_ShouldExcludeRecentlyRecommended() { // 生成用户ID var userIdArb = Gen.Choose(1, 1000); var recommendUserIdArb = Gen.Choose(1001, 2000); // 生成推荐日期(0-10天前) var daysAgoArb = Gen.Choose(0, 10); return Prop.ForAll( userIdArb.ToArbitrary(), recommendUserIdArb.ToArbitrary(), daysAgoArb.ToArbitrary(), (userId, recommendUserId, daysAgo) => { // Arrange - 创建模拟的推荐记录 var existingRecommends = new List { new DailyRecommend { UserId = userId, RecommendUserId = recommendUserId, RecommendDate = DateTime.Today.AddDays(-daysAgo), CreateTime = DateTime.Now.AddDays(-daysAgo) } }; // Act var isRecentlyRecommended = RecommendService.IsRecommendedInDaysStatic( existingRecommends, userId, recommendUserId, RecommendService.DeduplicationDays); // Assert // 如果推荐日期在3天内(包括今天),应该返回true // 如果推荐日期超过3天,应该返回false var expectedResult = daysAgo <= RecommendService.DeduplicationDays; return isRecentlyRecommended == expectedResult; }); } /// /// 今日推荐的用户应被标记为已推荐 /// [Property(MaxTest = 100)] public Property TodayRecommend_ShouldBeMarkedAsRecent() { var userIdArb = Gen.Choose(1, 1000); var recommendUserIdArb = Gen.Choose(1001, 2000); return Prop.ForAll( userIdArb.ToArbitrary(), recommendUserIdArb.ToArbitrary(), (userId, recommendUserId) => { // Arrange - 今日推荐 var existingRecommends = new List { new DailyRecommend { UserId = userId, RecommendUserId = recommendUserId, RecommendDate = DateTime.Today, CreateTime = DateTime.Now } }; // Act var isRecentlyRecommended = RecommendService.IsRecommendedInDaysStatic( existingRecommends, userId, recommendUserId, RecommendService.DeduplicationDays); // Assert - 今日推荐应该被标记为已推荐 return isRecentlyRecommended; }); } /// /// 3天前推荐的用户应被标记为已推荐 /// [Property(MaxTest = 100)] public Property ThreeDaysAgoRecommend_ShouldBeMarkedAsRecent() { var userIdArb = Gen.Choose(1, 1000); var recommendUserIdArb = Gen.Choose(1001, 2000); return Prop.ForAll( userIdArb.ToArbitrary(), recommendUserIdArb.ToArbitrary(), (userId, recommendUserId) => { // Arrange - 3天前推荐 var existingRecommends = new List { new DailyRecommend { UserId = userId, RecommendUserId = recommendUserId, RecommendDate = DateTime.Today.AddDays(-3), CreateTime = DateTime.Now.AddDays(-3) } }; // Act var isRecentlyRecommended = RecommendService.IsRecommendedInDaysStatic( existingRecommends, userId, recommendUserId, RecommendService.DeduplicationDays); // Assert - 3天前推荐应该被标记为已推荐(边界情况) return isRecentlyRecommended; }); } /// /// 4天前推荐的用户不应被标记为已推荐 /// [Property(MaxTest = 100)] public Property FourDaysAgoRecommend_ShouldNotBeMarkedAsRecent() { var userIdArb = Gen.Choose(1, 1000); var recommendUserIdArb = Gen.Choose(1001, 2000); return Prop.ForAll( userIdArb.ToArbitrary(), recommendUserIdArb.ToArbitrary(), (userId, recommendUserId) => { // Arrange - 4天前推荐 var existingRecommends = new List { new DailyRecommend { UserId = userId, RecommendUserId = recommendUserId, RecommendDate = DateTime.Today.AddDays(-4), CreateTime = DateTime.Now.AddDays(-4) } }; // Act var isRecentlyRecommended = RecommendService.IsRecommendedInDaysStatic( existingRecommends, userId, recommendUserId, RecommendService.DeduplicationDays); // Assert - 4天前推荐不应该被标记为已推荐 return !isRecentlyRecommended; }); } /// /// 不同用户的推荐记录不应影响当前用户 /// [Property(MaxTest = 100)] public Property DifferentUserRecommend_ShouldNotAffectCurrentUser() { var userIdArb = Gen.Choose(1, 500); var otherUserIdArb = Gen.Choose(501, 1000); var recommendUserIdArb = Gen.Choose(1001, 2000); return Prop.ForAll( userIdArb.ToArbitrary(), otherUserIdArb.ToArbitrary(), recommendUserIdArb.ToArbitrary(), (userId, otherUserId, recommendUserId) => { // Arrange - 其他用户的推荐记录 var existingRecommends = new List { new DailyRecommend { UserId = otherUserId, // 不同的用户 RecommendUserId = recommendUserId, RecommendDate = DateTime.Today, CreateTime = DateTime.Now } }; // Act var isRecentlyRecommended = RecommendService.IsRecommendedInDaysStatic( existingRecommends, userId, // 当前用户 recommendUserId, RecommendService.DeduplicationDays); // Assert - 其他用户的推荐记录不应影响当前用户 return !isRecentlyRecommended; }); } /// /// 空推荐列表应返回未推荐 /// [Property(MaxTest = 100)] public Property EmptyRecommendList_ShouldReturnNotRecommended() { var userIdArb = Gen.Choose(1, 1000); var recommendUserIdArb = Gen.Choose(1001, 2000); return Prop.ForAll( userIdArb.ToArbitrary(), recommendUserIdArb.ToArbitrary(), (userId, recommendUserId) => { // Arrange - 空推荐列表 var existingRecommends = new List(); // Act var isRecentlyRecommended = RecommendService.IsRecommendedInDaysStatic( existingRecommends, userId, recommendUserId, RecommendService.DeduplicationDays); // Assert - 空列表应返回未推荐 return !isRecentlyRecommended; }); } /// /// 去重天数常量应为3 /// [Fact] public void DeduplicationDays_ShouldBe3() { Assert.Equal(3, RecommendService.DeduplicationDays); } }