2013-12-22 78 views
0
[TestMethod] 
    public void Can_Login_With_Valid_Credentials() 
    { 
     //Arrange 
     Mock<IMembershipRepository> mockRepository = new Mock<IMembershipRepository>();   

     Mock<LoginViewModel> mockModel = new Mock<LoginViewModel>(); 
     mockModel.Setup(x => x.IsLoggedIn()).Returns(true);    

     AccountController target = new AccountController(mockRepository.Object); 

     //Act 
     ActionResult result = target.Login(mockModel.Object); 

     //Assert 
     Assert.IsNotInstanceOfType(result, typeof(ViewResult)); 

    } 

而且在的ActionResult控制器我可以爲我正在測試的方法中創建的對象創建一個方法嗎?

public ActionResult Login(LoginViewModel viewModel) 
    { 
     string returnUrl = (string)TempData["ReturnUrl"];   

     if (ModelState.IsValid) 
     { 
      LoginViewModel model = new LoginViewModel(repository, viewModel); 

      if (model.IsLoggedIn()) 
      { 
       if (String.IsNullOrEmpty(returnUrl)) return RedirectToAction("Index", "Home"); 
       else return Redirect(returnUrl); 
      } 
      else 
      { 
       ModelState.AddModelError("Email", ""); 
       ModelState.AddModelError("Password", ""); 
      } 
     } 

     return View(viewModel); 
    } 

我在與在ActionMethod嘲諷model.IsLoggedIn()問題,可能是因爲我在ActionMethod創建視圖模型LoginViewModel的新實例。這就是爲什麼在單元測試中mockModel.Setup(x => x.IsLoggedIn()).Returns(true);沒有緩存它,因爲存在具有該方法的類的新實例。

有什麼辦法可以在ActionMethod中模擬model.IsLoggedIn()並讓它返回true

+3

確實是這個問題。是否有一個特定的原因,你創建一個新的'LoginViewModel'對象,而不是操縱現有的? –

+0

總之,沒有。你試圖嘲笑一個具體的實現。如果依賴關係沒有被注入,你不能嘲笑它。您傳入的「LoginViewModel」實例不是實際調用「IsLoggedIn」的實例,因此設置不匹配。 – levelnis

+0

只有TypeMock Isolator或Fakes可以幫助你。通過一些重構,你可以很容易地測試這個,在你的控制器中創建一個受保護的虛擬CreateLoginViewModel將允許你通過正常的模擬工具來操作它。或者像Jeroen建議的那樣重新使用模型。 – jessehouwing

回答

2

如果沒有辦法避免在操作方法中創建LoginViewModel的新實例,那麼引入一個工廠來做到這一點。不惜一切代價直接創建任何具體的類 - 這使得單元測試成爲不可能。

如果action方法使用工廠創建一個對象,那麼具體工廠作爲控制器的構造函數參數傳遞。這需要IoC容器和自定義控制器工廠,添加到項目中相對比較簡單。

使用此解決方案時,單元測試實際上會模擬工廠,以便模擬的工廠返回模擬的LoginViewModel對象(實際上是實現ILoginViewModel接口的模擬對象)。這是我在所有MVC項目中完成的方式,並且完美適用於生產代碼,單元測試和集成測試。

+0

感謝您的好主意!這就是我現在要做的。 –

0

根據上述評論和研究,最好的方法是使用現有的LoginViewModel,而不是創建一個新的實例。這裏是與Moq合作的ActionResult的重新構想的願景。

public ActionResult Login(LoginViewModel viewModel) 
    { 
     string returnUrl = (string)TempData["ReturnUrl"];   

     if (ModelState.IsValid) 
     { 
      if (viewModel.IsLoggedIn(repository)) 
      { 
       if (String.IsNullOrEmpty(returnUrl)) return RedirectToAction("Index", "Home"); 
       else return Redirect(returnUrl); 
      } 
      else 
      { 
       ModelState.AddModelError("Email", ""); 
       ModelState.AddModelError("Password", ""); 
      } 
     } 

     return View(viewModel); 
    } 
相關問題