Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.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 如何在ASP.net MVC中正确测试具有数据库调用的控制器_Asp.net Mvc_Unit Testing_Moq_Mstest - Fatal编程技术网

Asp.net mvc 如何在ASP.net MVC中正确测试具有数据库调用的控制器

Asp.net mvc 如何在ASP.net MVC中正确测试具有数据库调用的控制器,asp.net-mvc,unit-testing,moq,mstest,Asp.net Mvc,Unit Testing,Moq,Mstest,我正在开发一个ASP.net MVC 3.0应用程序。我正在使用MSTest和Moq进行单元测试。我已经为我的控制器编写了所有的测试方法,并运行了这些测试,获得了成功的结果 现在,我怀疑我是否正确地进行了单元测试。因为,我的大多数控制器操作都包含数据库调用 我不是在模仿它们,我只是在模仿使用Moq的会话和请求对象 因为单元测试意味着测试单个代码单元,所以真的有必要模拟数据库调用吗?我认为使用数据库调用对控制器进行单元测试违反了上述陈述 如果是这样,有人能解释一下如何模拟数据库调用吗?我没有使用任

我正在开发一个ASP.net MVC 3.0应用程序。我正在使用
MSTest
Moq
进行单元测试。我已经为我的控制器编写了所有的测试方法,并运行了这些测试,获得了成功的结果

现在,我怀疑我是否正确地进行了单元测试。因为,我的大多数控制器操作都包含数据库调用

我不是在模仿它们,我只是在模仿使用Moq的
会话
请求
对象

因为单元测试意味着测试单个代码单元,所以真的有必要模拟数据库调用吗?我认为使用数据库调用对控制器进行单元测试违反了上述陈述

如果是这样,有人能解释一下如何模拟数据库调用吗?我没有使用任何实体框架

更新2:

[httppost]
  public void AjaxSave(Model m)
{
   m.update(); // Database call
}

您应该将进行数据库调用的代码提取到单独的对象中(请看)。你有一个控制器

public class PersonController : Controller
{
     public ActionResult Index()
     { 
         var connectionString = 
             ConfigurationManager.ConnectionStrings["foo"].ConnectionString;
         using(var connection = new SqlConnection(connectionString))
         {
             string sql = "SELECT Name FROM People";
             var command = connection.CreateCommand(sql);
             var reader = command.ExecuteReader();
             List<Person> people = new List<Person>();
             while(reader.Read())
             {
                 Person p = new Person();
                 p.Name = reader["Name"].ToString();
                 people.Add(p);
             }

             return View(people);
         }
     }
}
然后将存储库实现注入控制器()并模拟它进行测试:

var repositoryMock = new Mock<IPersonRepository>();
var people = new List<People>(); // provide some sample list 
repositoryMock.Setup(r => r.GetAllPeople()).Return(people);
var controller = new PersonController(repositoryMock.Object);

var result = (ViewResult)controller.Index();
// Assert here
Assert.AreEqual(result.ViewName, "Index");
Assert.AreEqual(result.Model, people);
repositoryMock.VerifyAll();
var repositoryMock=new Mock();
var people=新列表();//提供一些样本清单
repositoryMock.Setup(r=>r.GetAllPeople()).Return(people);
var controller=newpersoncontroller(repositoryMock.Object);
var result=(ViewResult)controller.Index();
//在此断言
Assert.AreEqual(result.ViewName,“Index”);
Assert.AreEqual(result.Model,people);
repositoryMock.VerifyAll();

好吧,我认为您在这里有一些设计问题,因为适当的可测试代码永远不会在MVC控制器中与数据库代码一起结束,您需要更好地实现关注点分离,以便每段代码都是可单元测试的,这是通过使用一些设计模式实现的,例如Service Factory,依赖注入和控制反转…如果你不知道我在说什么,Joel Abrahamsson解释得很好。您甚至可以查看,这是一个非常好的开源工具(控制反转)

您仍然可以花点力气对控制器进行单元测试,在单元测试中实现设置函数和清理函数。但是,我强烈建议,如果你有一点时间,重构你的代码,你不会有太多不必要的依赖关系


Leo

控制器永远不应该直接调用数据库(其中一个——不是最重要的——原因是这使得控制器几乎不可能进行测试…)。相反,我强烈建议您重构代码,以便首先启用可测试性,并具有适当的功能:将所有数据访问代码放入其中,然后通过接口在控制器中进行访问。这样,你就可以很容易地用Moq来模仿他们。

@leo..如何从controller@Leo..i我不是直接调用数据库,而是使用模型方法调用。@lazyberezovsky.您能给我一个示例测试吗method@Avinash欢迎:)我还向示例测试方法添加了几个断言。最后一个验证您为模拟存储库设置的所有依赖项调用是否成功发生(即,您可能会忘记从数据库中获取人员)@Lazyberezovsky..请您解释一下测试方法,到底是什么happening@Is数据库调用发生在这里?@Avinash不,你正在传递模拟对象。在控制器看来,它与普通存储库完全相同。此模拟已设置为在不访问任何真实数据库的情况下返回人员。所以,若控制器向存储库请求人员列表,它将得到您创建的列表。最后一行测试验证了控制器是否向存储库询问了人员。@Thomas..请查找我问题的更新部分,这是我目前正在做的事情。单击save,我正在进行一个ajax调用,它将获得更新的模型。然后调用model.update()将这些值保存到数据库中。我应该如何重构上述方法。请建议。
public interface IPersonRepository
{
    List<Person> GetAllPeople();
    // other data access API will go here
}
public class PersonController : Controller
{
     private IPersonRepository _personRepository;

     public PersonController(IPersonRepository personRepository)
     {
         _personRepository = personRepository;
     }

     public ActionResult Index()
     { 
         var people = _personRepository.GetAllPeople();
         return View(people);             
     }
}
var repositoryMock = new Mock<IPersonRepository>();
var people = new List<People>(); // provide some sample list 
repositoryMock.Setup(r => r.GetAllPeople()).Return(people);
var controller = new PersonController(repositoryMock.Object);

var result = (ViewResult)controller.Index();
// Assert here
Assert.AreEqual(result.ViewName, "Index");
Assert.AreEqual(result.Model, people);
repositoryMock.VerifyAll();