Нулевая сессия в модульном тесте - PullRequest
0 голосов
/ 30 апреля 2018

Я пытаюсь написать некоторые модульные тесты для довольно простых действий контроллера, в которых я устанавливаю Session ["User"]. Когда я запускаю тест, он терпит неудачу в этой точке с исключением нулевой ссылки. Не совсем уверен, как обойти это.

Контроллер:

public ActionResult Index(int id)
        {
            Session["User"] = Id;

            if (Id != 0)
            {
                return RedirectToAction("Home", "Home", new { Id});
            }

            return RedirectToAction("Register", "Home", new { Id});
        }

Тест:

[TestMethod]
        public void NewUser_ShouldGoToRegister()
        {
            var controller = new HomeController();

            HttpContext.Current = FakeHttpContext();

            HttpContext.Current.Session.Add("User", "0");

            var result = controller.Index(0) as ViewResult;

            Assert.AreEqual("Register", result.ViewName);
        }


        public HttpContext FakeHttpContext()
        {
            var httpRequest = new HttpRequest("", "http://localhost/", "");

            var httpResponce = new HttpResponse(new 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 });


            HttpContext.Current = httpContext;
        }

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Если у вас есть трудности с этим, эта идея может помочь вам переосмыслить это. Иногда полезно создать еще один уровень доступа к Session.

Упрощенным способом было бы никогда не обращаться напрямую к «Сессии», а вместо этого заключить его в такие методы:

protected virtual string ReadFromSession(string key)
{
    return Session[key];
}

protected virtual void StoreInSession(string key, string value)
{
    Session[key] = value;
}

Везде в вашем контроллере, вы просто используете эти методы вместо прямого доступа к Session. Достаточно просто.

Теперь хитрость в том, что с модульным тестом вы можете переопределить тестируемый контроллер:

public class MyControllerForTesting : MyController
{
    private readonly IDictionary session;

    public MyControllerForTesting(IDictionary session) : base()
    {
        this.session = session;
    }

    protected override string ReadFromSession(string key)
    {
        return this.session[key];
    }

    protected override void StoreInSession(string key, string value)
    {
        this.session[key] = value;
    }
}

Теперь это может не сработать сразу, потому что я не проверял, но вы поняли идею. Ваши модульные тесты работают, и вы даже можете проверить Словарь, если значения были установлены правильно и т. Д.

0 голосов
/ 30 апреля 2018

Вы можете использовать какой-нибудь инструмент для насмешки, например, MOQ для насмешки, для создания фальшивого HttpContext вы можете попробовать как следующий код.

[TestMethod]
public void NewUser_ShouldGoToRegister()
{
    var controller = new HomeController();
    HttpContext.Current = FakeHttpContext();
    HttpContext.Current.Session.Add("User", 1);
    var result = controller.Index(0) as ViewResult;
    Assert.AreEqual("Register", result.ViewName);
}

Ваш FakeHttpContext метод должен выглядеть следующим образом.

        //Creating a Fake HTTP Context           
        // This is used for testing methods using Session Variables.
        private HttpContext FakeHttpContext()
        {
            var httpRequest = new HttpRequest("", "http://somethig.com/", "");
            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;
        }
...