202 votes

Définition de HttpContext.Current.Session dans un test unitaire

J'ai un service web que je suis en train de test de l'unité. Dans le service, il tire plusieurs valeurs à partir de la HttpContext comme suit:

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

dans l'unité de test je suis de la création du contexte à l'aide d'un simple ouvrier demande, comme suit:

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

Cependant, chaque fois que j'essaie de régler les valeurs de HttpContext.Actuel.Session

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

Je reçois référence nulle exception qui dit HttpContext.Actuel.La Session est null. Est-il possible d'initialiser la session en cours au sein de l'unité de test?

321voto

Milox Points 1983

Vous pouvez "faire semblant" en créant un nouveau httpcontext comme ceci:

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

J'ai pris ce code et l'ai mis sur une classe d'assistance statique comme:

 public static HttpContext FakeHttpContext()
{
    var httpRequest = new HttpRequest("", "http://stackoverflow/", "");
    var stringWriter = new StringWriter();
    var httpResponce = new HttpResponse(stringWriter);
    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 });

    return httpContext;
}
 

et alors vous pouvez l'appeler sur vos tests unitaires comme:

 HttpContext.Current = MockHelper.FakeHttpContext();
 

110voto

Anthony Shaw Points 4652

Nous avons eu à se moquer de HttpContext à l'aide d'un HttpContextFactory et de l'appel de l'usine depuis l'intérieur de notre application ainsi que les Tests Unitaires

public class HttpContextFactory
{
    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;
    }
}

Vous suffira alors de remplacer tous les appels à des HttpContext.Current avec HttpContextFactory.Current et ont accès aux mêmes méthodes. Puis, quand vous faites des tests, vous pouvez également accéder à la HttpContextFactory et de la fantaisie à vos attentes

C'est un exemple d'utilisation 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;
}

et puis de l'utiliser au sein de vos tests unitaires, je l'appelle dans mon Test de la méthode Init

HttpContextFactory.SetCurrentContext(GetMockedHttpContext());

vous pouvez ensuite, dans la méthode ci-dessus, ajouter les résultats attendus de la Séance que vous craignez d'être à la disposition de votre service web.

49voto

giammin Points 5027

La solution Milox est meilleure que celle acceptée, à mon humble avis, mais j’ai eu quelques problèmes avec cette implémentation lors de la gestion des URL avec une chaîne de requête .

J'ai apporté quelques modifications pour que cela fonctionne correctement avec toutes les URL et éviter Reflection.

 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;
}
 

43voto

Ro Hit Points 81

J'écris quelque chose à ce sujet il y a un moment.

Test unitaire de HttpContext.Current.Session dans MVC3 .NET

J'espère que cela aide.

 [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);
}
 

13voto

Nimblejoe Points 166

Si vous utilisez l’infrastructure MVC, cela devrait fonctionner. J’ai utilisé FakeHttpContext de Milox et ajouté quelques lignes de code supplémentaires. L’idée est venue de ce post :

http://codepaste.net/p269t8

Cela semble fonctionner dans MVC 5. Je n’ai pas essayé ceci dans les versions antérieures de MVC.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X