Asp.net mvc 如何使用Moq测试从数据库返回列表的索引操作?
我正在学习使用ASP.NETMVC5的单元测试和Moq。我正试图为我的一个控制器的索引操作编写我的第一个单元测试 下面是索引操作的代码Asp.net mvc 如何使用Moq测试从数据库返回列表的索引操作?,asp.net-mvc,unit-testing,asp.net-mvc-5,moq,mstest,Asp.net Mvc,Unit Testing,Asp.net Mvc 5,Moq,Mstest,我正在学习使用ASP.NETMVC5的单元测试和Moq。我正试图为我的一个控制器的索引操作编写我的第一个单元测试 下面是索引操作的代码 [Authorize] public class ExpenseController : Controller { private ApplicationDbContext db = new ApplicationDbContext(); // GET: /Expense/ public ActionResult Index()
[Authorize]
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId()));
}
}
我只想检查返回的视图是否为null
像这样的
[TestMethod]
public void ExpenseIndex()
{
// Arrange
ExpenseController controller = new ExpenseController();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
当然,这不起作用,因为连接到数据库和使用ApplicationSerid,所以你们能帮我进行moq和单元测试吗?或者给我推荐一个教程,让我熟悉ASP.NET MVC中的模拟 一种方法是将依赖项抽象封装在虚拟方法中,例如:创建一个返回用户费用的虚拟方法,现在控制器应该如下所示:
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(GetUserExpenses());
}
protected virtual List<Expense> GetUserExpenses()
{
return db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId());
}
}
public class ExpenseControllerStub : ExpenseController
{
protected override List<Expense> GetUserExpenses()
{
return new List<Expense>();
}
}
这是如何手动完成的。如果需要为此使用模拟框架,则需要将GetUserExpenses设置为不受保护的公共,然后进行设置以返回空的费用列表,如:
var mock = new Moq.Mock<ExpenseController>();
mock.Setup(m => m.GetUserExpenses().Returns(new List<Expense>());
但是我不想公开这个方法!可能有一种方法可以让Moq配置/设置受保护的方法,但我不知道
编辑:一个更好的解决方案是完全抽象费用存储库,在这种情况下,直接模拟它
另一种解决方案是将DbContext注入控制器构造函数,并使用模拟框架来模拟它和DbSet。您可以找到这样做的示例
Edit2:您还可以使用或使MVC测试更容易。将依赖项抽象到数据库/dbcontext,然后您可以将其模拟到controller@Nkosi你能给我提供更多的信息吗。谢谢。您的控制器对ApplicationDbContext有一个很强的依赖性,这使得在单元测试中很难进行模拟。您将需要重构dbcontext,以从公开dbcontext功能的抽象继承,然后让控制器依赖于该抽象而不是具体化。从那里,您可以使用DI框架将依赖项注入控制器,现在您还可以灵活地在测试中使用模拟实现替换抽象,如果需要的话,这显然不是您真正的控制器。该.ToList基本上是从[Expenses]中选择的*,它会将整个表拉入服务器,然后在内存中进行过滤。感谢您的回答,虽然它可以解决当前的问题,但它并不是一个实际的解决方案。我目前正在阅读您在最后提到的关于如何抽象存储库的文章,如果您能提供帮助,我将不胜感激:不,这是一个非常实用的解决方案,特别是当您使用遗留代码时。这可能是你能做的少数几件事中最简单的一件。根据您的需要,存储库实现有许多变体,EF已经为您的DbSet实现了一个通用存储库。无论如何,我已经用一个关于如何模拟DbContext和DbSet的外部链接更新了我的答案
var mock = new Moq.Mock<ExpenseController>();
mock.Setup(m => m.GetUserExpenses().Returns(new List<Expense>());