development

테스트 초기화 메소드의 HttpContext.Current 모의

big-blog 2020. 5. 27. 08:09
반응형

테스트 초기화 메소드의 HttpContext.Current 모의


내가 작성한 ASP.NET MVC 응용 프로그램에 단위 테스트를 추가하려고합니다. 내 단위 테스트에서 다음 코드를 사용합니다.

[TestMethod]
public void IndexAction_Should_Return_View() {
    var controller = new MembershipController();
    controller.SetFakeControllerContext("TestUser");

    ...
}

컨트롤러 컨텍스트를 조롱하는 다음 도우미를 사용하십시오.

public static class FakeControllerContext {
    public static HttpContextBase FakeHttpContext(string username) {
        var context = new Mock<HttpContextBase>();

        context.SetupGet(ctx => ctx.Request.IsAuthenticated).Returns(!string.IsNullOrEmpty(username));

        if (!string.IsNullOrEmpty(username))
            context.SetupGet(ctx => ctx.User.Identity).Returns(FakeIdentity.CreateIdentity(username));

        return context.Object;
    }

    public static void SetFakeControllerContext(this Controller controller, string username = null) {
        var httpContext = FakeHttpContext(username);
        var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller);
        controller.ControllerContext = context;
    }
}

이 테스트 클래스는 다음과 같은 기본 클래스에서 상속됩니다.

[TestInitialize]
public void Init() {
    ...
}

이 방법 내에서 다음 코드를 실행하려고하는 라이브러리 (제어 할 수없는)를 호출합니다.

HttpContext.Current.User.Identity.IsAuthenticated

이제 문제를 볼 수 있습니다. 컨트롤러에 대해 가짜 HttpContext를 설정했지만이 기본 Init 메소드에는 없습니다. 단위 테스트 / 조롱은 나에게 매우 새롭기 때문에 이것이 올바르게 이루어지고 싶습니다. 내 컨트롤러와 Init 메소드에서 호출 된 모든 라이브러리에서 HttpContext를 공유하도록 HttpContext를 모의 아웃하는 올바른 방법은 무엇입니까?


HttpContext.CurrentSystem.Web.HttpContext확장하지 않는 의 인스턴스를 반환합니다 System.Web.HttpContextBase. HttpContextBase나중에 HttpContext조롱하기 어려운 문제를 해결 하기 위해 추가되었습니다 . 두 클래스는 기본적으로 관련이 없습니다 (두 클래스 HttpContextWrapper사이의 어댑터로 사용됨).

다행스럽게도 (User) 및을 HttpContext대체하기에 충분할 정도로 가짜 입니다.IPrincipalIIdentity

다음 코드는 콘솔 응용 프로그램에서도 예상대로 실행됩니다.

HttpContext.Current = new HttpContext(
    new HttpRequest("", "http://tempuri.org", ""),
    new HttpResponse(new StringWriter())
    );

// User is logged in
HttpContext.Current.User = new GenericPrincipal(
    new GenericIdentity("username"),
    new string[0]
    );

// User is logged out
HttpContext.Current.User = new GenericPrincipal(
    new GenericIdentity(String.Empty),
    new string[0]
    );

Test Init 아래에서도 작업이 수행됩니다.

[TestInitialize]
public void TestInit()
{
  HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));
  YourControllerToBeTestedController = GetYourToBeTestedController();
}

나는 이것이 오래된 주제라는 것을 알고 있지만 단위 테스트를 위해 MVC 응용 프로그램을 조롱하는 것은 우리가 매우 정기적으로하는 일입니다.

I just wanted to add my experiences Mocking a MVC 3 application using Moq 4 after upgrading to Visual Studio 2013. None of the unit tests were working in debug mode and the HttpContext was showing "could not evaluate expression" when trying to peek at the variables.

Turns out visual studio 2013 has issues evaluating some objects. To get debugging mocked web applications working again, I had to check the "Use Managed Compatibility Mode" in Tools=>Options=>Debugging=>General settings.

I generally do something like this:

public static class FakeHttpContext
{
    public static void SetFakeContext(this Controller controller)
    {

        var httpContext = MakeFakeContext();
        ControllerContext context =
        new ControllerContext(
        new RequestContext(httpContext,
        new RouteData()), controller);
        controller.ControllerContext = context;
    }


    private static HttpContextBase MakeFakeContext()
    {
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var user = new Mock<IPrincipal>();
        var identity = new Mock<IIdentity>();

        context.Setup(c=> c.Request).Returns(request.Object);
        context.Setup(c=> c.Response).Returns(response.Object);
        context.Setup(c=> c.Session).Returns(session.Object);
        context.Setup(c=> c.Server).Returns(server.Object);
        context.Setup(c=> c.User).Returns(user.Object);
        user.Setup(c=> c.Identity).Returns(identity.Object);
        identity.Setup(i => i.IsAuthenticated).Returns(true);
        identity.Setup(i => i.Name).Returns("admin");

        return context.Object;
    }


}

And initiating the context like this

FakeHttpContext.SetFakeContext(moController);

And calling the Method in the controller straight forward

long lReportStatusID = -1;
var result = moController.CancelReport(lReportStatusID);

If your application third party redirect internally, so it is better to mock HttpContext in below way :

HttpWorkerRequest initWorkerRequest = new SimpleWorkerRequest("","","","",new StringWriter(CultureInfo.InvariantCulture));
System.Web.HttpContext.Current = new HttpContext(initWorkerRequest);
System.Web.HttpContext.Current.Request.Browser = new HttpBrowserCapabilities();
System.Web.HttpContext.Current.Request.Browser.Capabilities = new Dictionary<string, string> { { "requiresPostRedirectionHandling", "false" } };

참고URL : https://stackoverflow.com/questions/4379450/mock-httpcontext-current-in-test-init-method

반응형