2010-05-22 4 views
0

이 질문을 많이 편집하고 단순화했습니다. 내 HomeController에이 방법이 있다면왜이 asp.net mvc 단위 테스트가 실패합니까?

:

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

나는 일반적으로, 나는 좋은 조건을 테스트하는 한 널 조건을 테스트하기 위해 테스트 및 다른 것 이해하지만 내 삭제 컨트롤러를 테스트하는 동안 나는이 문제에 달렸다. 삭제 테스트에서는 일반적으로 레코드를 가져 와서 레코드를 삭제 한 다음 다시 가져 오려고합니다. 그것은 두 번째 가져올 때 null이어야하지만 그렇지 않습니다. 그래서, 나는 위에서 설명한대로 문제를 해결했다.

삭제를 테스트하는 적절한 방법이 아닌 경우 어떻게할까요? 레코드가 실제로 삭제되었는지 확인하지 않아도됩니까?

답변

1

당신은 다시 안 여러 요청을 처리하는 컨트롤러. 여기에서 수행중인 작업과 정확히 동일합니다.

어쨌든, 당신이 확인하는 경우 source code for MVC이 동작에 대한 이유 확인할 수있는 것들 : 모델이 null의

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

테스트 대상이 명확하지 않습니다. 테스트 메소드의 Arrange 섹션에서 첫 번째 Delete 액션을 호출하고 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

게시 한 컨트롤러 삭제 방법에는 두 가지가 있습니다. 첫 번째는 삭제할 상태를 검색하고 두 번째는 실제 삭제를 수행하는 메서드입니다. _stateService 변수는 인터페이스를 기반으로하고 Unit 테스트를 위해 FakeStateRepoditory에 모든 것을 전달하는 내 상태 서비스의 인스턴스입니다. 내 TestInitialize는 모든 것을 설정하므로 각 테스트에 대해 데이터를 구성합니다. 정렬은 내가 삭제하고 싶은 레코드를 얻고 있고, 행위는 그것을 삭제하려고 시도하고 다시 가져오고, 자산은 그것이 null인지 확인하고 우리가 Index 메소드로 되돌려 보내 졌음을 확인합니다. –

+0

더 명확히하기 위해, 여러 삭제 테스트를 통해 첫 번째 삭제 컨트롤러 메서드가 올바른보기 데이터를 반환하는지 확인하여 존재하지 않는 레코드를 삭제하려고하면 올바른 위치로 리다이렉트되었는지 확인합니다. 이 특별한 테스트는 레코드가 실제로 삭제되도록합니다. 그렇게하기 위해서, 나는 그것을 가져 와서 삭제하고, 다시 가져 와서 그것이 사라 졌는지 확인해야한다. –

+0

메서드를 사용하려고하면 HomeController_Delete_Action_Handler_Should_Redirect_If_Model_Successfully_Delete 테스트에서 다음 오류가 발생합니다. 결과의 Values ​​컬렉션에서 'controller'라는 매개 변수를 찾을 수 없습니다. 변경된 경우 : .AssertActionRedirect() .ToAction ("Index"); 작동합니다. 그러나 나는 당신의 방법을 선호합니다. 내가 뭘 잘못하고 있는지 알아? –

관련 문제