[C#] 단위 테스트에서 HttpContext.Current.Session 설정

단위 테스트를 시도하는 웹 서비스가 있습니다. 서비스에서 다음 HttpContext과 같은 여러 값을 가져옵니다 .

 m_password = (string)HttpContext.Current.Session["CustomerId"];
 m_userID = (string)HttpContext.Current.Session["CustomerUrl"];

단위 테스트에서 간단한 작업자 요청을 사용하여 컨텍스트를 작성합니다.

SimpleWorkerRequest request = new SimpleWorkerRequest("", "", "", null, new StringWriter());
HttpContext context = new HttpContext(request);
HttpContext.Current = context;

그러나 값을 설정하려고 할 때마다 HttpContext.Current.Session

HttpContext.Current.Session["CustomerId"] = "customer1";
HttpContext.Current.Session["CustomerUrl"] = "customer1Url";

null이라는 예외 참조 HttpContext.Current.Session가 나타납니다.

단위 테스트 내에서 현재 세션을 초기화하는 방법이 있습니까?



답변

우리는 단위 테스트뿐만 아니라 응용 프로그램 내에서 HttpContexta를 사용 HttpContextManager하고 공장을 호출 하여 조롱해야했습니다.

public class HttpContextManager 
{
    private static HttpContextBase m_context;
    public static HttpContextBase Current
    {
        get
        {
            if (m_context != null)
                return m_context;

            if (HttpContext.Current == null)
                throw new InvalidOperationException("HttpContext not available");

            return new HttpContextWrapper(HttpContext.Current);
        }
    }

    public static void SetCurrentContext(HttpContextBase context)
    {
        m_context = context;
    }
}

그런 다음에 어떤 통화를 대체 할 것이다 HttpContext.CurrentHttpContextManager.Current같은 방법에 액세스 할 수 있습니다. 그런 다음 테스트 할 때 HttpContextManager기대치에 액세스 하고 조롱 할 수도 있습니다.

다음은 Moq 사용 예입니다 .

private HttpContextBase GetMockedHttpContext()
{
    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>();
    var urlHelper = new Mock<UrlHelper>();

    var routes = new RouteCollection();
    MvcApplication.RegisterRoutes(routes);
    var requestContext = new Mock<RequestContext>();
    requestContext.Setup(x => x.HttpContext).Returns(context.Object);
    context.Setup(ctx => ctx.Request).Returns(request.Object);
    context.Setup(ctx => ctx.Response).Returns(response.Object);
    context.Setup(ctx => ctx.Session).Returns(session.Object);
    context.Setup(ctx => ctx.Server).Returns(server.Object);
    context.Setup(ctx => ctx.User).Returns(user.Object);
    user.Setup(ctx => ctx.Identity).Returns(identity.Object);
    identity.Setup(id => id.IsAuthenticated).Returns(true);
    identity.Setup(id => id.Name).Returns("test");
    request.Setup(req => req.Url).Returns(new Uri("http://www.google.com"));
    request.Setup(req => req.RequestContext).Returns(requestContext.Object);
    requestContext.Setup(x => x.RouteData).Returns(new RouteData());
    request.SetupGet(req => req.Headers).Returns(new NameValueCollection());

    return context.Object;
}

그런 다음 단위 테스트에서 사용하려면 Test Init 메소드 내에서 이것을 호출하십시오.

HttpContextManager.SetCurrentContext(GetMockedHttpContext());

그런 다음 위의 방법으로 웹 서비스에서 사용할 수있을 것으로 예상되는 Session의 예상 결과를 추가 할 수 있습니다.


답변

다음 HttpContext과 같이 새로운 것을 만들어 “가짜”를 만들 수 있습니다 .

http://www.necronet.org/archive/2010/07/28/unit-testing-code-that-uses-httpcontext-current-session.aspx

그 코드를 가져 와서 정적 도우미 클래스에 넣었습니다.

public static HttpContext FakeHttpContext()
{
    var httpRequest = new HttpRequest("", "http://example.com/", "");
    var stringWriter = new StringWriter();
    var httpResponse = new HttpResponse(stringWriter);
    var httpContext = new HttpContext(httpRequest, httpResponse);

    var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
                                            new HttpStaticObjectsCollection(), 10, true,
                                            HttpCookieMode.AutoDetect,
                                            SessionStateMode.InProc, false);

    httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
                                BindingFlags.NonPublic | BindingFlags.Instance,
                                null, CallingConventions.Standard,
                                new[] { typeof(HttpSessionStateContainer) },
                                null)
                        .Invoke(new object[] { sessionContainer });

    return httpContext;
}

또는 대신 새로운 구성하기 위해 반사를 사용하는 HttpSessionState인스턴스를, 당신은 당신을 첨부 할 수 있습니다 HttpSessionStateContainer받는 사람 HttpContext(브렌트 M. 맞춤법의 의견에 따라) :

SessionStateUtility.AddHttpSessionStateToContext(httpContext, sessionContainer);

그런 다음 단위 테스트에서 다음과 같이 호출 할 수 있습니다.

HttpContext.Current = MockHelper.FakeHttpContext();


답변

Milox 솔루션 은 허용되는 IMHO보다 낫지 만 querystring으로 URL을 처리 할 때이 구현에 문제가있었습니다 .

URL에서 제대로 작동하고 리플렉션을 피하기 위해 변경했습니다.

public static HttpContext FakeHttpContext(string url)
{
    var uri = new Uri(url);
    var httpRequest = new HttpRequest(string.Empty, uri.ToString(),
                                        uri.Query.TrimStart('?'));
    var stringWriter = new StringWriter();
    var httpResponse = new HttpResponse(stringWriter);
    var httpContext = new HttpContext(httpRequest, httpResponse);

    var sessionContainer = new HttpSessionStateContainer("id",
                                    new SessionStateItemCollection(),
                                    new HttpStaticObjectsCollection(),
                                    10, true, HttpCookieMode.AutoDetect,
                                    SessionStateMode.InProc, false);

    SessionStateUtility.AddHttpSessionStateToContext(
                                         httpContext, sessionContainer);

    return httpContext;
}


답변

나는 얼마전에 이것에 대해 뭔가를 걱정한다.

MVC3 .NET에서 HttpContext.Current.Session의 단위 테스트

도움이 되길 바랍니다.

[TestInitialize]
public void TestSetup()
{
    // We need to setup the Current HTTP Context as follows:            

    // Step 1: Setup the HTTP Request
    var httpRequest = new HttpRequest("", "http://localhost/", "");

    // Step 2: Setup the HTTP Response
    var httpResponce = new HttpResponse(new StringWriter());

    // Step 3: Setup the Http Context
    var httpContext = new HttpContext(httpRequest, httpResponce);
    var sessionContainer = 
        new HttpSessionStateContainer("id", 
                                       new SessionStateItemCollection(),
                                       new HttpStaticObjectsCollection(), 
                                       10, 
                                       true,
                                       HttpCookieMode.AutoDetect,
                                       SessionStateMode.InProc, 
                                       false);
    httpContext.Items["AspSession"] = 
        typeof(HttpSessionState)
        .GetConstructor(
                            BindingFlags.NonPublic | BindingFlags.Instance,
                            null, 
                            CallingConventions.Standard,
                            new[] { typeof(HttpSessionStateContainer) },
                            null)
        .Invoke(new object[] { sessionContainer });

    // Step 4: Assign the Context
    HttpContext.Current = httpContext;
}

[TestMethod]
public void BasicTest_Push_Item_Into_Session()
{
    // Arrange
    var itemValue = "RandomItemValue";
    var itemKey = "RandomItemKey";

    // Act
    HttpContext.Current.Session.Add(itemKey, itemValue);

    // Assert
    Assert.AreEqual(HttpContext.Current.Session[itemKey], itemValue);
}


답변

MVC 프레임 워크를 사용하는 경우 이것이 작동합니다. Milox의 FakeHttpContext를 사용 하고 몇 줄의 코드를 추가했습니다. 아이디어는이 게시물에서 나왔습니다.

http://codepaste.net/p269t8

이것은 MVC 5에서 작동하는 것 같습니다. 이전 버전의 MVC에서는 이것을 시도하지 않았습니다.

HttpContext.Current = MockHttpContext.FakeHttpContext();

var wrapper = new HttpContextWrapper(HttpContext.Current);

MyController controller = new MyController();
controller.ControllerContext = new ControllerContext(wrapper, new RouteData(), controller);

string result = controller.MyMethod();


답변

FakeHttpContext 시도 할 수 있습니다 :

using (new FakeHttpContext())
{
   HttpContext.Current.Session["CustomerId"] = "customer1";       
}


답변

asp.net Core / MVC 6 rc2에서 HttpContext

var SomeController controller = new SomeController();

controller.ControllerContext = new ControllerContext();
controller.ControllerContext.HttpContext = new DefaultHttpContext();
controller.HttpContext.Session = new DummySession();

rc 1은

var SomeController controller = new SomeController();

controller.ActionContext = new ActionContext();
controller.ActionContext.HttpContext = new DefaultHttpContext();
controller.HttpContext.Session = new DummySession();

https://stackoverflow.com/a/34022964/516748

사용을 고려하십시오 Moq

new Mock<ISession>();