2010-06-21 3 views
11

Index 컨트롤러의 동작을 테스트하려고합니다. 작업은 AutoMapper을 사용하여 Customer 도메인의 개체를보기 모델 TestCustomerForm에 매핑합니다. 이것이 작동하는 동안 나는 Index 조치로부터받은 결과를 테스트하는 가장 좋은 방법에 대해 우려하고 있습니다.Automapper를 사용하여 ViewModel을 매핑 한 후 테스트 할 대상과 테스트는 무엇입니까?

public ActionResult Index() 
{ 
    TestCustomerForm cust = Mapper.Map<Customer, 
     TestCustomerForm>(_repository.GetCustomerByLogin(CurrentUserLoginName)); 

    return View(cust); 
} 

그리고 그 TestMethod은 다음과 같습니다 :

는 컨트롤러의 index 액션은 다음과 같다 내가 고객 저장소를 조롱하고 그것을 설정하는 Rhino.Mocks를 사용하는 CreateTestController 방법에서

[TestMethod] 
public void IndexShouldReturnCustomerWithMachines() 
{ 
    // arrange 
    var customer = SetupCustomerForRepository(); // gets a boiler plate customer 
    var testController = CreateTestController(); 

    // act 
    ViewResult result = testController.Index() as ViewResult; 

    // assert 
    Assert.AreEqual(customer.MachineList.Count(), 
     (result.ViewData.Model as TestCustomerForm).MachineList.Count()); 
} 

SetupCustomerForRepository에서 고객을 반품하십시오. 이 방식으로 나는 Index 작업이 _repository.GetCustomerByLogin(CurrentUserLoginName)을 호출 할 때 저장소가 의도 한 고객을 반환 할 것임을 알고 있습니다. 따라서, 나는 균등 한 숫자가 IndexShouldReturnCustomerWithMachines을 만족시키기에 충분하다고 주장한다.

모든 것은 내가 테스트해야하는 것에 관해서 우려한다고 말했다.

  1. result.ViewData.Model as TestCustomerForm을 사용하는 것이 좋습니다. 이게 진짜 문제 야? 이 문제는 저에게 해당됩니다. 왜냐하면이 테스트에서는 테스트 개발을 실제로 수행하지 않고 테스트를 만족시키기 위해 특정 구현을 믿고있는 것처럼 보입니다.
  2. 올바른 매핑을 보장하기위한 적절한 테스트가 있습니까?
  3. 각 매핑 된 속성을 TestCustomerForm에서 테스트해야합니까?
  4. 더 일반적인 컨트롤러 동작 테스트가 있습니까? 당신이 컨트롤러에이 통과

    public interface IMapper<TSource, TDest> 
    { 
        TDest Map(TSource source); 
    } 
    
    public CustomerToTestCustomerFormMapper: IMapper<Customer, TestCustomerForm> 
    { 
        static CustomerToTestCustomerFormMapper() 
        { 
         // TODO: Configure the mapping rules here 
        } 
    
        public TestCustomerForm Map(Customer source) 
        { 
         return Mapper.Map<Customer, TestCustomerForm>(source); 
        } 
    } 
    

    다음 :

답변

15

이것이 AutoMapper를 사용자 지정 ActionResult 또는 ActionFilter로 이동시킨 이유 중 하나입니다. 어떤 시점에서 Foo를 FooDto에 매핑했는지 테스트하고 싶지만 실제로 매핑을 테스트 할 필요는 없습니다. AutoMapper를 레이어 경계 (예 : 컨트롤러와 뷰 사이)로 이동하면 AutoMapper에 수행 할 작업을 테스트 할 수 있습니다.

이는 ViewResult 테스트와 비슷합니다. 컨트롤러에서 뷰를 렌더링 한 것이 아니라 MVC에 그러한 뷰를 렌더링하도록 지시 한 것입니다.우리의 행동의 결과가된다 : 기본 컨트롤러 클래스에 도우미 메서드와

public class AutoMapViewResult : ActionResult 
{ 
    public Type SourceType { get; private set; } 
    public Type DestinationType { get; private set; } 
    public ViewResult View { get; private set; } 

    public AutoMapViewResult(Type sourceType, Type destinationType, ViewResult view) 
    { 
     SourceType = sourceType; 
     DestinationType = destinationType; 
     View = view; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     var model = Mapper.Map(View.ViewData.Model, SourceType, DestinationType); 

     View.ViewData.Model = model; 

     View.ExecuteResult(context); 
    } 
} 

: 다음 컨트롤러를 만드는

protected AutoMapViewResult AutoMapView<TDestination>(ViewResult viewResult) 
{ 
    return new AutoMapViewResult(viewResult.ViewData.Model.GetType(), typeof(TDestination), viewResult); 
} 

을 이제 대신 실제 매핑을 수행하는,로/매핑을 지정 :

이 시점에서
public ActionResult Index(int minSessions = 0) 
{ 
    var list = from conf in _repository.Query() 
       where conf.SessionCount >= minSessions 
       select conf; 

    return AutoMapView<EventListModel[]>(View(list)); 
} 

, 난 단지 실제로 mappi을 수행 할 필요없이, "이 대상 FooDto 유형이 푸 개체를 매핑하고 있는지 확인하십시오", 테스트해야 ng.

EDIT :

여기에서 테스트 조각의 예 :

var actionResult = controller.Index(); 

actionResult.ShouldBeInstanceOf<AutoMapViewResult>(); 

var autoMapViewResult = (AutoMapViewResult) actionResult; 

autoMapViewResult.DestinationType.ShouldEqual(typeof(EventListModel[])); 
autoMapViewResult.View.ViewData.Model.ShouldEqual(queryResult); 
autoMapViewResult.View.ViewName.ShouldEqual(string.Empty); 
+0

많은 의미가있는 훌륭한 대답입니다. 후손을 위해 시험 진술을 추가 하시겠습니까? – ahsteele

+1

내 Get 메서드가 동작 결과가 아닌 IEnumerable 을 반환하는 새 WebApi에서 어떻게 작동합니까? – shashi

+0

@sassyboy 필자는 웹 API를 사용하여 고립 된 서비스 레이어를 사용하는 경향이있다. 웹 애플리케이 션에서는 비슷한 추상화를 만들 수있다. –

2

아마 AutoMapper 사이의 결합 및 추상화를 도입하여 컨트롤러 분리 할

public HomeController: Controller 
{ 
    private readonly IMapper<Customer, TestCustomerForm> _customerMapper; 
    public HomeController(IMapper<Customer, TestCustomerForm> customerMapper) 
    { 
     _customerMapper = customerMapper; 
    } 

    public ActionResult Index() 
    { 
     TestCustomerForm cust = _customerMapper.Map(
      _repository.GetCustomerByLogin(CurrentUserLoginName) 
     ); 
     return View(cust); 
    } 
} 

그리고 당신의 단위 테스트에 당신 좋아하는 조롱 프레임 워크를 사용하여이 매퍼를 스텁합니다.

+0

이러한 테스트 값의 하위 단부에있다. 오토 매퍼 (AutoMapper)가 정확히 테스트하고있는 것을 모의 해보면 그 맵이 호출됩니까? 흐름 로직 등은 없다. 단지 테스트 커버리지를 높일 수있다. 귀하의 컨트롤러가 얇을 때 (복잡성이 바인더, 필터, 액션 인보커 등으로 옮겨 졌을 때) "단위 테스트"(불꽃 기다림) –

+0

@mattcodes,이 컨트롤러 동작은 테스트해야 할 세 가지 일을합니다. 저장소를 사용하면 (모의!)이 저장소의 결과가 다른 유형 (모의!)으로 매핑되면 매핑 결과가보기로 돌아갑니다. 이 저장소가 데이터를 가져오고 매핑이 수행되는 방식이 컨트롤러에 낮은 가치가있는 경우 별도로 테스트해야합니다. 물론 대안으로 테스트 할 필요는 없지만 OP 질문은 단위 테스트에 관한 것이므로 두 개의 센트를 제공하기로 결정했습니다 :-) –

관련 문제