2010-05-22 211 views
0

我已經編輯和簡化了這個問題了很多。爲什麼這個asp.net mvc單元測試失敗?

如果我有我的HomeController這種方法:

public ActionResult Strangeness(int id) 
    { 
     StrangenessClass strangeness = null; 

     if(id == 1) 
     { 
      strangeness = new StrangenessClass() { Name="Strangeness", Desc="Really weird behavior" }; 
     } 

     return View(strangeness); 
    } 

而且有這個類:

public class StrangenessClass 
{ 
    public string Name { get; set; } 
    public string Desc { get; set; } 
} 

爲什麼這個單元測試失敗?

[TestMethod] 
    public void Strangeness() 
    { 
     HomeController controller = new HomeController(); 

     ViewResult result = controller.Strangeness(1) as ViewResult; 
     var model = result.ViewData.Model; 
     result = controller.Strangeness(2) as ViewResult; 
     model = result.ViewData.Model; 

     Assert.IsNull(model); 
    } 

我明白,通常情況下,我將有一個測試,測試空狀態,另一個測試了良好的條件,但我遇到了這個問題,同時測試我刪除控制器。在刪除測試中,我通常會獲取記錄,刪除記錄,然後嘗試再次獲取記錄。我第二次拿到它應該是空的,但事實並非如此。所以,我如上所述解決了問題。

如果這不是測試刪除的正確方法,那麼您會怎麼做?你不需要確保記錄實際上被刪除了嗎?

回答

1

你不應該重用一個控制器來處理多個請求,這正是你在這裏做的。

無論如何,如果你檢查source code for MVC你會發現這種現象的原因:

protected internal virtual ViewResult View(string viewName, string masterName, object model) 
{ 
    if (model != null) 
    { 
     base.ViewData.Model = model; 
    } 
    return new ViewResult { ViewName = viewName, MasterName = masterName, ViewData = base.ViewData, TempData = base.TempData }; 
}

如果模型爲空,這不是分配給ViewData.Model屬性。 如果您想要正確的行爲,請爲您的第二個電話HomeController.Strangeness創建一個新的控制器。

0

目前尚不清楚你正在測試什麼。在你的測試方法的排列部分,你正在調用第一個刪除操作,在Act部分中你要調用第二個。那麼你在測試控制器嗎?如果是,那麼你爲什麼要調用編配部分中的第一個刪除方法?

又是什麼_stateService變量?它是一個接口,還是實際上是在單元/集成測試中刪除數據庫中的記錄?

所以我會建議你寫多個測試,每一個驗證被測主題的精確行爲,我認爲是控制器。所以你應該爲你正在測試的不同刪除操作分開單元測試。

假設_stateService是可以被嘲笑的接口,這是我會建議你設計的控制器,你的測試看起來是這樣的(使用Rhino MocksMVCContrib.TestHelper):

[TestClass] 
public class DevisControllerTests : TestControllerBuilder 
{ 
    private HomeController _sut; // Subject Under Test 
    private IStateService _stateServiceStub; // Dependency of the SUT 

    [TestInitialize()] 
    public void MyTestInitialize() 
    { 
     _stateServiceStub = MockRepository.GenerateStub<IStateService>(); 
     _sut = new HomeController(_stateServiceStub); 
     InitializeController(_sut); // this method comes from the base class TestControllerBuilder 
    } 

    [TestMethod] 
    public void HomeController_Delete_Action_Should_Fetch_State_From_Db_And_Pass_It_To_The_View() 
    { 
     // arrange 
     var id = 4; 
     var expectedState = new State(); 
     _stateServiceStub.Stub(x => x.GetById(id)).Return(expectedState); 

     // act 
     var actual = _sut.Delete(id); 

     // assert 
     actual 
      .AssertViewRendered() 
      .WithViewData<State>() 
      .ShouldBe(expectedState); 
    } 

    [TestMethod] 
    public void HomeController_Delete_Action_Handler_Should_Return_Default_View_If_Model_Null() 
    { 
     // act 
     var actual = _sut.Delete(null); 

     // assert 
     actual.AssertViewRendered(); 
    } 

    [TestMethod] 
    public void HomeController_Delete_Action_Handler_Should_Return_View_If_Exception_Thrown_From_Service() 
    { 
     // arrange 
     var model = new State(); 
     _stateServiceStub.Stub(x => x.Delete(model)).Throw(new Exception("oops")); 

     // act 
     var actual = _sut.Delete(state); 

     // assert 
     actual 
      .AssertViewRendered() 
      .WithViewData<State>() 
      .ShouldBe(model); 
    } 


    [TestMethod] 
    public void HomeController_Delete_Action_Handler_Should_Redirect_If_Model_Successfully_Deleted() 
    { 
     // arrange 
     var model = new State(); 

     // act 
     var actual = _sut.Delete(state); 

     // assert 
     actual 
      .AssertActionRedirect() 
      .ToAction<HomeController>(c => c.Index()); 

     _stateServiceStub.AssertWasCalled(x => x.Delete(model)); 
    } 

} 
+0

我發佈了兩個刪除控制器方法。第一個檢索要刪除的狀態,第二個post方法進行實際刪除。 _stateService變量是我的狀態服務的一個實例,它基於一個接口並將所有事情推遲到一個FakeStateRepoditory進行單元測試。我的TestInitialize設置所有這些,所以我已經爲每個測試組成了數據。該安排正在獲取我想刪除的記錄,該行爲正試圖刪除它,然後再次獲取它,並且該資產確保它爲空,並且我們被髮回到索引方法。 – 2010-05-22 16:59:22

+0

爲了進一步說明,我確實有多個刪除測試,以確保第一個刪除控制器方法返回正確的視圖數據,以確保如果我嘗試刪除不存在的記錄,並將其重定向到適當的位置,等這個特殊的測試,確保記錄實際上被刪除。要做到這一點,我必須抓取它,發送它被刪除,並試圖再次抓取它,以確保它不見了。 – 2010-05-22 17:07:49

+0

嘗試使用您的方法時,HomeController_Delete_Action_Handler_Should_Redirect_If_Model_Successfully_Delete測試中出現以下錯誤: 在結果的值集合中找不到名爲'controller'的參數。 如果將其更改爲: 實際 .AssertActionRedirect() .ToAction(「Index」); 它的工作原理。但是,我更喜歡你的方法。你知道我做錯了什麼嗎? – 2010-06-04 05:57:29

相關問題