2010-12-10 5 views
2

데이터를 ViewData로 채우는 컨트롤러를 단위 테스트하려고합니다. Google의 모든 견해에는 유사한 데이터 (URL에서 파생 된 고객 정보)가 필요합니다. 따라서 모든 단일 컨트롤러 메서드에 호출을 호출하는 대신 원래 개발자는이 ViewData를 OnActionExecuting 이벤트에 넣기로 결정했습니다.단위 테스트에서 ASP.NET MVC2 사용자 지정보기 엔진이 무시되었습니다.

물론 단위 테스트에서 컨트롤러의 동작을 호출하면 OnActionExecuting이 실행되지 않습니다. (Thanks MVC Team!)

그래서 사용자 정의 뷰 엔진을 생성하고 뷰가 요청 될 때 고객 데이터를 controllerContext에 채워 넣으려고했습니다. 브라우저에서 정상적으로 작동하지만이 테스트를 실행하면 내 viewEngine이 무시됩니다. ViewEngines.Add (new funkyViewEngine)의 효과는 없습니다.

[TestMethod()] 
      public void LoginTest() 
      { 
       ViewEngines.Engines.Clear(); 
       ViewEngines.Engines.Add(new FunkyViewEngine()); 

       UserController target = new UserController(); 
       target.SetStructureMap(); <--sets us to use the test repo 

       target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com"); <--moq magic 
       var actual = target.Login(); 
       Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult))); 
       var vr = actual as ViewResult; 
       Assert.IsTrue(vr.ViewData.Community() != null); <--"Community" should be set by viewengine 
       Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain"); 
       Assert.IsTrue(vr.ViewData.Community().CanRegister); 
      } 

여기에 희망이 있습니까? 어떻게하면 1) 브라우저와 유닛 프레임 워크에서 컨트롤러 실행시 호출되는 메소드를 생성하거나 2) 내 뷰 엔진을 호출하는 유닛 프레임 워크를 얻는 방법.

답변

2

죄송합니다. 유닛 테스트에서 액션 메소드를 직접 호출 할 때 OnActionExecuting이 호출되지 않는 이유는 그것이 MVC에서의 작동 방식이 아니기 때문입니다.

요청은이 영역과 관련하여 ControllerActionInvoker으로 이루어진 "파이프 라인"을 통해 실행됩니다.

  1. 액션 필터 'OnActionExecuting 방법 호출 액션 메소드
  2. 찾기 :이 클래스가 담당 : 액션 메소드 자체
  3. 를 호출
  4. (메모를 컨트롤러 클래스는 액션 필터도) 동작 필터 호출 'OnActionExecuted 메서드
  5. 결과 처리 (예 :보기 찾기 및 렌더링)

유닛 테스트에서 3 단계를 직접 호출하고 다른 모든 단계를 건너 뜁니다. 단위 테스트에서는 작업을 수행하는 데 필요한 설정 코드를 호출하는 것은 사용자의 책임입니다.

그러나 이것은 이제 전체 파이프 라인을 실행하기 위해 ControllerActionInvoker을 사용하는 단위 테스트를 작성해야한다는 것을 의미하지 않습니다. 우리 (MVC 팀)는 이미 모든 부분이 함께 작동하는지 확인했습니다.

대신 특정 응용 프로그램 코드를 테스트해야합니다.이 경우, 다음과 같은 단위 테스트를 고려해 있습니다

  1. 컨트롤러에 OnActionExecuting를 호출하는 일부 URL 주어진이을 ViewData에 있는지 확인
  2. 테스트를 올바른 고객 객체를두고 있는지 확인 시험 일부 고객 부여 ViewData에있는 객체입니다. 동작 메서드가 적절한 결과를 반환합니다.

마지막으로 요점은 OnActionExecuting의 기능을 유지해야한다는 것입니다. 커스텀 뷰 엔진은 확실히 틀린 장소입니다.

+0

예, ViewEngine은이 동작으로 인해 사소한 컨트롤러를 완전히 테스트 할 수 없게 만듭니다. 나에게 OnActionExecuting 및 OnActionExecuted를 호출하고 수동으로 호출하는 공용 래퍼를 배치 할 수 있지만 RoleFilter, SessionFilter, RequireHttps 등과 같은 내 특성에는 도움이되지 않습니다. –

+0

응용 프로그램과 신뢰를 구성하는 구성 요소를 개별적으로 테스트해야합니다 :) 프레임 워크가 모든 것을 함께 작동하게 만들 것입니다. 예를 들어 필터 속성의 경우 리플렉션을 사용하여 속성이 메소드에 선언되었는지 확인할 수 있습니다. MVC는 테스트 할 수 있도록 설계되었으며 프레임 워크 자체를 테스트하려고 할 때만 어렵습니다. 이와 같은 문제에 부딪치게되면 다른 접근 방식을 취해야한다는 것을 알 수 있습니다. – marcind

+0

MyController.Action이 http를 https로 올바르게 리디렉션하고 사용자를 로그인했는지 확인하기 위해 유닛 테스트를 사용할 수 없다는 것은 여전히 ​​완전히 파손되어 있습니다. 팀을 드래그하여 TDD쪽으로 비명을 지르려는 사람들은 MVC 팀이 테스트를 해치고 있습니다. . –

0

아마도 당신이 찾고있는 대답은 아니지만 동일한 목표 (멀티 테넌트 앱에서 고객을 얻는 것)를 달성하기 위해 MvcHandler 사용자 지정을 사용하고 있습니다. ViewEngine는

내 사용자 정의 핸들러가 더 많거나 적은 같은 외모 ... 나에게 로직 이런 종류의 좋은 장소 같은 소리하지 않습니다 당신의 좌절에 대한

public class AccountMvcHandler : MvcHandler 
{ 
    public Account Account { get; private set; } 

    protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) 
    { 
     return base.BeginProcessRequest(httpContext, callback, state); 
    } 

    protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) 
    { 
     string accountName = this.RequestContext.RouteData.GetRequiredString("account"); 
     Account = ServiceFactory.GetService<ISecurityService>().GetAccount(accountName); 

     return base.BeginProcessRequest(httpContext, callback, state); 
    } 
} 
+0

조금 설명해 주시겠습니까? ViewEngine 해킹은 단위 테스트 접근법에서 액션 와이어 링이 부족한 것을 그냥 추한 것입니다. 더 좋은 방법이 있다면, 나는 듣고 싶습니다. –