2013-12-11 92 views
5

我正在一個ASP.net MVC 3.0應用程序。我正在使用MSTest以及Moq進行單元測試。我已經爲我的控制器編寫了所有的測試方法,並運行了這些測試,並取得了成功的結果。如何正確測試ASP.net MVC中的控制器有數據庫調用

現在,我懷疑我是否已經進行了適當的單元測試。因爲,我的控制器操作幾乎大部分都包含數據庫調用。

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

真的有必要模擬數據庫調用,因爲單元測試意味着測試單個代碼單元嗎?我認爲帶數據庫調用的單元測試控制器違反了上述說法。

如果是這樣,任何人都可以解釋我如何模擬數據庫調用?我沒有使用任何實體框架。

Updated2:

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

回答

10

你應該提取代碼,這使得數據庫調用轉換爲單獨的對象(取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); 
     } 
    } 
} 

提取數據訪問代碼放到單獨的類(通常這樣叫repositories類):

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

然後注入倉庫實現到控制器(Dependency Injection in .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(); 
+0

@ lazyberezovsky..can請你給我一個樣品測試方法 –

+0

@Avinash是,已經添加 –

+1

@ layberezovsky..Super example..Thank你這麼多.. –

1

嗯,我覺得你有一些設計問題在這裏,因爲適當的測試代碼絕不會與數據庫代碼最終內一個MVC控制器,您需要更好地實現關注點分離,以便每段代碼都是單元可測試的,並且通過使用一些設計模式(如Service Factory,依賴注入和控制反轉)來實現... Joel Abrahamsson解釋它非常漂亮以及如果你不知道我在說什麼,那麼就是here。你甚至可以檢查出Castle Windsor,這是一個非常好的開源工具(控制反轉)

你仍然可以通過一點努力在你的控制器上進行單元測試,在你的程序中執行設置函數和清理函數單元測試。但是,我強烈建議,如果你有一點時間,REFACTOR你的代碼,你會得到很多不必要的依賴關係。

利奧

+0

@ leo ..如何從控制器調用模型 –

+0

@ Leo ..我不直接調用數據庫,而是使用模型方法調用。 –

1

控制器從未應該直接調用數據庫(一個 - 不是最重要的 - 原因是,這使得控制器幾乎不可能測試...)。相反,我強烈建議您使用重構您的代碼,以便首先啓用可測試性,同時還要有適當的Separation of Concerns:將所有數據訪問代碼放入Repositories,然後通過接口在控制器中訪問。這樣,你可以輕鬆地用Moq嘲笑他們。

+0

@托馬斯..請發現我的問題的更新部分,這是如何,我目前正在做。點擊保存,我正在進行ajax調用,即獲取更新後的模型。然後我調用model.update()將這些值保存到數據庫。我應該如何重構以上method.Please建議。 –

相關問題