.NET中Xunit测试无法拦截餐盒重复预约问题求助
问题:同一取餐日期重复预约餐盒的测试未触发预期错误
我开发了一个食物浪费系统,学生可低价预约餐盒并取餐。现在编写Xunit测试验证「同一取餐日期不可预约2份餐盒」的规则,但测试中餐盒仍被成功预约,未触发预期的错误提示。尝试调整餐盒添加方式无效,恳请排查问题原因。
测试代码
[Fact] //unhappy public void MealBox_Student_Already_Reserved_Same_Date() { // Arrange var repositoryManagerMock = new Mock<IRepositoryManager>(); ServiceManager _ss = new ServiceManager(repositoryManagerMock.Object); var MealboxList = new List<MealBox>(); var Student = new Student { Id = 1, FirstName = "Test", LastName = "Student", Email = "test@gmail.com", DateOfBirth = DateTime.Now.AddYears(-15), StudentNumber = "210897", StudyCity = City.Breda, MobileNumber = "0612345678", ReservedMealBoxes = MealboxList }; MealboxList.Add(new MealBox { Id = 1, Name = "Test MealBox", PickupDateTime = DateTime.Now.AddDays(1), LatestPickupTime = DateTime.Now.TimeOfDay, IndicationalIs18Plus = false, IsHotMeal = false, Price = 10, MealType = MealType.ColdLunch, ExampleProductsBasedOnHistory = new List<Product>(), ReservedBy = Student, ReservedById = 1, OfferedAtCanteen = null, OfferedAtCanteenId = 1 }); var MealBox = new MealBox { Id = 2, Name = "Test MealBox", PickupDateTime = DateTime.Now.AddDays(1), LatestPickupTime = DateTime.Now.TimeOfDay, IndicationalIs18Plus = false, IsHotMeal = false, Price = 10, MealType = MealType.ColdLunch, ExampleProductsBasedOnHistory = new List<Product>(), ReservedBy = null, ReservedById = null, OfferedAtCanteen = null, OfferedAtCanteenId = 1 }; repositoryManagerMock.Setup(x => x.MealBox.GetById(2)).Returns(MealBox); repositoryManagerMock.Setup(x => x.Student.GetByEmail(Student.Email)).Returns(Student); // Act ServiceResponse message = _ss.MealBox.Reserve(2, Student.Email); // Assert Assert.Equal("You have already reserved a mealbox for this date", message.Message); }
验证器代码
public ServiceResponse Reserve(int id, string email) { var response = new ServiceResponse(); var student = _repositoryManager.Student.GetByEmail(email); if (student == null) { response.Success = false; response.Message = "Student not found"; return response; } var mealBox = _repositoryManager.MealBox.GetById(id); if (mealBox == null) { response.Success = false; response.Message = "MealBox not found"; return response; } var resultOfChecks = MealBoxReserveChecks(response, mealBox, student); if (!resultOfChecks.Success) { return resultOfChecks; } mealBox.ReservedById = student.Id; try { _repositoryManager.MealBox.Update(mealBox); _repositoryManager.Save(); } catch (Exception ex) { throw ex; } response.Success = true; response.Message = "MealBox reserved successfully!"; return response; } private ServiceResponse MealBoxReserveChecks(ServiceResponse response, MealBox mealBox, Student student) { if (mealBox.ReservedBy != null) { response.Success = false; response.Message = "MealBox already reserved"; return response; } if (mealBox.IndicationalIs18Plus) { int hasToBePickedUp = Int32.Parse(mealBox.PickupDateTime.ToString("yyyyMMdd")); int dateOfBirth = Int32.Parse(student.DateOfBirth.ToString("yyyyMMdd")); if (((hasToBePickedUp - dateOfBirth) / 10000) < 18) { response.Success = false; response.Message = "You are not 18+ and cannot reserve this mealbox"; return response; } } var reservedMealBoxes = _repositoryManager.MealBox.GetAll().Where(mb => mb.ReservedById == student.Id).ToList(); if (reservedMealBoxes.Any(mb => mb.PickupDateTime.Day == mealBox.PickupDateTime.Day)) { response.Success = false; response.Message = "You have already reserved a mealbox for this date"; return response; } response.Success = true; return response; }
问题原因及修复方案
核心问题
- 模拟数据源缺失:验证逻辑通过
_repositoryManager.MealBox.GetAll()查询学生已预约餐盒,但测试中未对该方法做模拟设置,默认返回空集合,导致检测不到已存在的同日期预约。 - 日期判断逻辑不严谨:仅用
PickupDateTime.Day比较天数,会把不同月份的同一天(如1月1日和2月1日)误判为同一日期。
修复步骤
1. 补充GetAll()方法的模拟
在测试的Arrange部分添加以下代码,让仓储返回包含已预约餐盒的完整集合:
var allMealBoxes = new List<MealBox> { MealboxList.First(), // 学生已预约的餐盒(Id=1) MealBox // 待预约的餐盒(Id=2) }; repositoryManagerMock.Setup(x => x.MealBox.GetAll()).Returns(allMealBoxes);
2. 修正日期比较逻辑
将验证器中的日期判断改为比较Date属性,确保年、月、日完全匹配:
if (reservedMealBoxes.Any(mb => mb.PickupDateTime.Date == mealBox.PickupDateTime.Date)) { response.Success = false; response.Message = "You have already reserved a mealbox for this date"; return response; }
3. 可选:固定测试时间避免干扰
测试中使用DateTime.Now可能因执行时差导致日期不一致,可提前定义固定日期:
var pickupDate = DateTime.Now.AddDays(1).Date; // 已预约餐盒的PickupDateTime PickupDateTime = pickupDate, // 待预约餐盒的PickupDateTime PickupDateTime = pickupDate,
内容的提问来源于stack exchange,提问作者Joep Donkers
相关产品推荐
相关产品推荐

