gpt4 book ai didi

c# - 使用存储库对基本 C# 应用程序进行单元测试

转载 作者:太空宇宙 更新时间:2023-11-03 14:47:41 24 4
gpt4 key购买 nike

我有一个基本的 .NET 应用程序,我被要求为其编写单元测试,但单元测试总是让我感到困惑。

此应用程序有两个存储库(FoodRepository 和 DrinkRepository),它们从硬编码列表返回数据。

这是 Program.cs:

public static void Main(string[] args)
{
var foodSvc = new FoodService();
var foodId = 12;
var grade = 98.2d;
foodSvc.UpdateFoodGrade(foodId, grade);
}

调用:

public void UpdateFoodGrade(int foodId, double grade)
{
var foodRepo = new FoodRepository();
var food = foodRepo.GetFood(foodId);

food.Grade = grade;

if (!food.IsPassed)
{
var drinkRepository = new DrinkRepository();
var drink = drinkRepository.GetDrink(foodId);

if (grade >= drink.MinimumPassingGrade)
{
food.IsPassed = true;
}
else
{
food.IsPassed = false;
}
}
}

我的问题是,这里的人通常会为此做哪些单元测试?而且,我可以举一些例子吗?

一直在谷歌搜索和研究这个问题,但这个概念仍然让我难以理解。

我一直在测试环境中使用完整的集成测试,并没有真正完成单元测试。

如果有人需要更多代码来帮助解决这个问题,请告诉我。我 super 卡住了。

谢谢

更新:

感谢下面的内容,我得到了很多进一步的帮助,但我仍然坚持进行其余的测试。这是我更新后的服务的样子:

public class FoodService
{
private readonly FoodRepository _foodRepo;
private readonly DrinkRepository _drinkRepository;

public FoodService(FoodRepository foodRepo, DrinkRepository drinkRepository)
{
_foodRepo = foodRepo;
_drinkRepository = drinkRepository;
}

public void UpdateFoodGrade(int foodId, double grade)
{
var food = _foodRepo.GetFood(foodId);

food.Grade = grade;

if (!food.IsPassed)
{
var drink = _drinkRepository.GetDrink(foodId);

if (grade >= drink.MinimumPassingGrade)
{
food.IsPassed = true;
}
else
{
food.IsPassed = false;
}
}
}
}

更新主要内容:

public class Program
{
public static void Main(string[] args)
{
var foodRepository = new FoodRepository();
var drinkRepository = new DrinkRepository();
var foodSvc = new FoodService(foodRepository, drinkRepository);

var foodId = 12;
var grade = 98.2d;

foodSvc.UpdateFoodGrade(foodId, grade);
}
}

到目前为止测试(我不知道下一步该做什么)

[TestMethod]
public void UpdateFoodGrade_Test()
{
//Arrange
var foodId = 12;
var grade = 98.2d;
var expected = true;

var food = new Food() { FoodId = foodId };
var drink = new Drink() { DrinkId = foodId };

var foodRepositoryMock = new Mock<FoodRepository>();
foodRepositoryMock.Setup(m => m.GetFood(foodId)).Returns(food).Verifiable();

var drinkRepositoryMock = new Mock<DrinkRepository>();
drinkRepositoryMock.Setup(m => m.GetDrink(foodId)).Returns(drink).Verifiable();

var foodService = new FoodService(foodRepositoryMock.Object, drinkRepositoryMock.Object);

//Act
var actual = foodService.UpdateFoodGrade(foodId, grade);

//Assert
foodRepositoryMock.Verify();
drinkRepositoryMock.Verify();
Assert.AreEqual(expected, actual);
}
}

编辑 2:

我继续对界面等进行重构。这是它的效果:

[TestMethod]
public void UpdateLessonGrade_IsPassingGrade()
{
//Arrange
var lessonId = 12;

var lesson = new Lesson() { LessonId = lessonId };
var module = new Module() { ModuleId = lessonId };

var lessonRepositoryMock = new Mock<ILessonRepository>();
lessonRepositoryMock.Setup(x => x.GetLesson(lessonId)).Returns(lesson);

var moduleRepositoryMock = new Mock<IModuleRepository>();
moduleRepositoryMock.Setup(x => x.GetModule(lessonId)).Returns(module);

var lessonService = new LessonService(lessonRepositoryMock.Object, moduleRepositoryMock.Object);

//Act
lessonService.UpdateLessonGrade(12, 98.2d);

//Assert
Assert.IsTrue(lesson.IsPassed); // assuming it should pass in this condition
Assert.AreEqual(98.2d, lesson.Grade); // expected Lesson Grade should be what you expected the grade to be after you call UpdateLessonGrade
}

最佳答案

我现在在移动设备上,我可以尝试在本周末晚些时候更新答案,但这应该能让你开始。

重构您的方法以使用实例变量而不是在方法中直接实例化。将它们作为参数添加到您的构造函数中。在 main 方法中创建您的存储库实例并将它们传递给服务构造函数。

现在您可以使用诸如 Moq 之类的东西或 Entity Framework 的内存提供程序。

至于测试什么,基本上就是测试每一条分支逻辑。至少,每个 if 语句和 else 条件。您还应该测试当您的存储库对象找不到您要查找的内容时会发生什么(例如返回 null)。顺便说一下,我至少计算了六次测试。

更新:太棒了!查看您在问题中更新的代码,一切都在正确的轨道上。

在您的测试方法中,您需要添加:

var foodService = new FoodService(foodRepositoryMock.Object, drinkRepositoryMock.Object);

这将使用模拟对象初始化您的服务。

然后您需要使用如下测试参数调用您的服务:

foodService.UpdateFoodGrade(12, 98.2d);

最后一部分是使用如下断言检查您的食物对象:

Assert.IsTrue(food.IsPassed) // assuming it should pass in this condition
Assert.Equals(98.2d, food.Grade); // expectedFoodGrade should be what you expected the grade to be after you call UpdateFoodGrade

看起来您还需要进一步充实 Drink 对象的实例。您需要为 MinimumPassingGrade 指定一个值,因为它用于驱动 if 语句中的决策逻辑,例如,如果您希望触发 food.IsPassed = true,你会像这样实例化饮料对象:

var drink = new Drink() { DrinkId = foodId, MinimumPassingGrade = 50.0d };

您将为其他各种测试用例中的每一个创建测试方法,如果您在食物库中找不到食物,或者在饮料库中找不到饮料等,则不及格,当它等于分数时.

另一个注意事项,当您需要知道某个方法被调用/未被调用时,您只需要担心 Verifiable 模拟。对于这些测试,我可能不会验证是否调用了方法(在您的测试和实现与行为之间创建更紧密的耦合)。您希望验证是否仅当您的服务代码中的某些内容真正依赖于知道它被调用时才调用这些方法。例如如果您使用的是 Entity Framework 并且想确保没有忘记调用 SaveChanges()

关于c# - 使用存储库对基本 C# 应用程序进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53458667/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com