2

로 인해으로 HttpContext의 오류가 발생 HttpContext를 같이 :테스트 내 컨트롤러 내가 부르는 컨트롤러가 .NET MVC

public class AuthenticationService 
{ 
    private IPrincipal _user = HttpContext.Current.User; 

    ... 
} 

내 프로젝트 곳에서 :

[Authorize(Roles = "Administrador")] 
public class ApuradorController : Controller 
{ 
    private readonly Questiona2011Context _context = new Questiona2011Context(); 

    private readonly AuthenticationService _authenticationService = new AuthenticationService(); 
} 

으로 HttpContext는 AuthenticationService 클래스의 호출입니다 컨트롤러를 테스트 할 때 컨트롤러를 테스트하면 오류가 발생합니다. private IPrincipal _user = HttpContext.Current.User; 줄 : 객체 참조가 객체의 인스턴스로 설정되지 않았습니다.

컨트롤러를 테스트하려면 무엇이 필요합니까?

답변

3

가장 중요한 것은 테스트를 위해 ASP.NET MVC 프로젝트를 설계하는 방법에 대한 지식입니다.

종속성 삽입을 사용하도록 컨트롤러를 설계해야합니다. 즉, 컨트롤러는 AuthenticationService의 구체적인 구현을 사용해서는 안되며 IAuthenticationService를 사용하여 런타임에 구체적 구현이 제공됩니다. 지금은 컨트롤러가 생성 될 때 AuthenticationService도 생성됩니다. 그러나 테스트 시나리오에서 HttpContext는 null이고 NullReference 예외로 AuthenticationService 만들기가 실패합니다. 이 인터페이스를 통해 설계하면 테스트 목적으로 AuthenticationService의 가짜 구현을 컨트롤러에 제공하고 예외를 throw하지 않습니다.

public interface IAuthenticationService 
{ 
    IPrincipal User {get;} 
} 

public class AuthenticationService : IAuthenticationService 
{ 
    private IPrincipal _user = HttpContext.Current.User; 

    ... 
} 

//the controller 
[Authorize(Roles = "Administrador")] 
public class ApuradorController : Controller 
{ 
    private readonly Questiona2011Context _context = new Questiona2011Context(); 

    private readonly IAuthenticationService _authenticationService; 

    public ApuradorController(IAuthenticationService authenticationService) 
    { 
     _authenticationService = authenticationService; 
    } 
} 

테스트 시나리오에서는 예를 moq을 위해, 가짜 IAuthenticationService 구현을위한 약간의 조롱 라이브러리를 사용할 수 있습니다. 조롱을 통해 값을 제공하십시오.

var mockAuthenticationService = new Mock<IAuthenticationService>(); 
//setup mockAuthenticationService 

var controller = new ApuradorController(mockAuthenticationService.Object); 

이번에는 예외가 발생하지 않습니다.

위의 정보는 단위 테스트 가능 프로젝트 디자인의 원칙을 이해하지 못하는 경우 유용하지 않습니다. 빠른 시작을 위해 this 링크를 읽으십시오. 추가 읽기, 주소록에 대한 asp.net mvc, 나는 그들을 추천합니다 스티븐 샌더슨. 단위 테스트 할 수있는 컨트롤러 설계의 주된 아이디어는 가짜 구성 요소를 컨트롤러, 가짜 리포지토리, 서비스 등에 공급하고 유닛 테스트를 거친 컨트롤러의 일부만을 그대로 두는 것입니다. 그런 다음 위조 된 부분과 컨트롤러 반복을 테스트하십시오. 단위 테스트는 해당 상호 작용을 테스트하는 것을 의미합니다. 상호 작용이 올 바르면 해당 구성 요소의 실제 구현에서 올바를 것입니다. 그들이 틀리면 테스트가 실패합니다.

+0

내가 제안하는 것을해라 : var authenticationService = new Mock (); var 컨트롤러 = 새로운 ApuradorController (authenticationService); 하지만 예외가 발생했습니다 : 'Moq.Mock '매개 변수 형식 'App.Services.IAuthenticationService' –

+0

할당 할 수없는 새 ApuradorController (authenticationService.Object); 사용해야합니다. ? –

+0

네, 그렇게해야합니다. 또한 해당 모의 ApplicationService의 User 속성을 사용하려면 Setup()을 수행해야합니다. moq documentation wiki의 Setup()에 대해 읽어보십시오. - http://code.google.com/p/moq/wiki/QuickStart – archil

0

이 작업을 수행하려면 HttpContextBase를 조롱해야합니다. Hanselman의 article가 도움이 될 것입니다.

1

이것은 나에게 적절하지 않은 것으로 보입니다. 서비스 계층에 System.Web 네임 스페이스에 대한 종속성을 추가하고 있습니다. 사용자 이름을 서비스 계층에 전달하는 것이 더 좋을 것입니다. 아마도 생성자에서 가능할 수도 있으며, 기본 서비스 클래스의 생성자에서 사용하는 것이 가장 좋을 수 있으므로 모든 서비스 메소드에서 액세스 할 수 있습니다. 컨트롤러에서

abstract class BaseService 
{ 
    procteced IPrinciple _userName; 

    public BaseService(IPrinciple userName) 
    { 
     _userName = userName; 
    } 
} 

class AuthenticationService : BaseService 
{ 
    public AuthenticationService(IPrinciple userName) 
     :base(userName) 
    { 

    } 
} 

: 그런 아마도

AuthenticationService _service = new AuthenticationService(HttpContext.Current.User); 

- 당신이 등 역할 등을 액세스하는 위하여려고하는 경우에, 당신은 ASP.net 주위에 약간의 래퍼 클래스를 생성하는 것이 유용 할 수있다 역할/프로필 정보에 액세스하는 것과 같은 일을하기 위해 서비스 계층의 인터페이스를 구현하는 멤버십 클래스.

0

당신은 HttpContext를 (진짜) 철사 및 사용할 수 있습니다 :

// Arrange 
    HttpContext.Current = 
    new HttpContext(
     new HttpRequest("", "http://tempuri.org", ""), 
     new HttpResponse(new StringWriter())); 
    HttpContext.Current.User = new GenericPrincipal(new GenericIdentity("MyUser"), new[]{"Admin"}); 

    // Call your controller action... 

나는 개인적으로 여분의 마일을 가서 추상화의 또 다른 레이어를 추가하고 STH를 구축 할 것입니다. IPrincipalAccessor처럼 자세한 내용은 다른 답변을 참조하십시오.

1

컨트롤러를 단위 테스트하기 위해 다른 사람들은 실제 HTTP가 없기 때문에 런타임에 HTTP 컨텍스트 (요청, 응답 등)를 바꿀 수있는 방법으로 컨트롤러를 설계해야한다고 말했기 때문에 단위 테스트시 상황.

다른주의해야 할 점은 유닛 테스트 (ApuradorController.Index())를 통해 컨트롤러에서 액션을 호출 할 때 자동으로 ASP.NET과 동일한 실행 파이프 라인을 얻지는 않는다는 점입니다 MVC는 런타임을 제공하므로 "정상적인"실행의 일부인 이벤트 중 일부는 트리거되지 않습니다. 예를 들어, OnActionExecuting에서 일부 작업을 수행하면 장치 테스트에서 ApuradorController.Index()를 호출 할 때 해당 메서드가 자동으로 트리거되지 않습니다.

테스트 컨트롤러는 프로그래밍 방식을 변경해야하기 때문에 처음에는 어려울 수 있습니다. 최종 결과는 더 나은 코드이지만, 거기에 도달하는 데 약간의 어려움이있을 수 있습니다.

관련 문제