Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 如何使用Moq测试从数据库返回列表的索引操作?_Asp.net Mvc_Unit Testing_Asp.net Mvc 5_Moq_Mstest - Fatal编程技术网

Asp.net mvc 如何使用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()

我正在学习使用ASP.NETMVC5的单元测试和Moq。我正试图为我的一个控制器的索引操作编写我的第一个单元测试

下面是索引操作的代码

[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>());