Asp.net-Mvc

如何在具有數據庫呼叫的 ASP.net MVC 中正確測試控制器

  • December 11, 2013

我正在開發一個 ASP.net MVC 3.0 應用程序。我正在使用MSTestwithMoq進行單元測試。我已經為我的控制器編寫了所有的測試方法並執行了這些測試,得到了成功的結果。

現在,我懷疑我是否正確地進行了單元測試。因為,幾乎我的大多數控制器操作都包含數據庫呼叫。

我不是在嘲笑他們,我只是在嘲笑SessionRequest使用 Moq 的對象。

是否真的有必要模擬數據庫呼叫,因為單元測試意味著測試單個程式碼單元?我認為帶有數據庫呼叫的單元測試控制器違反了上述聲明。

如果是這樣,誰能解釋我如何模擬數據庫呼叫?我沒有使用任何實體框架。

更新2:

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

您應該提取使數據庫呼叫成為單獨對象的程式碼(查看Single Responsibility Principle)。例如你有控制器

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);
        }
    }
}

將數據訪問程式碼提取到單獨的類中(通常此類稱為儲存庫):

public class PersonRepository : IPersonRepository
{
    public List<Person> GetAllPeople()
    {
        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 people;
        }
    }
}

正如您已經註意到的那樣,我聲明了由數據訪問類實現的抽象:

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);             
    }
}

然後將儲存庫實現注入控制器(.NET 中的依賴注入)並模擬它以進行測試:

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

引用自:https://stackoverflow.com/questions/20512820