Статический помощник, использующий Session в MVC3, не дает мне пройти тестирование - PullRequest
0 голосов
/ 13 мая 2011

Я пишу проект на c # asp.net mvc3, и у меня есть вспомогательный класс, который выглядит следующим образом:

using System.Collections.Generic;
using System.Web;

namespace CoPrice.Helpers
{
    public static class Messages
    {
        public static IList<Message> All
        {
            get
            {
                var list = ((IList<Message>)HttpContext.Current.Session["_messages"]) ?? new List<Message>();
                HttpContext.Current.Session["_messages"] = new List<Message>();
                return list;
            }
        }

        public static bool Exists
        {
            get
            {
                return (((IList<Message>)HttpContext.Current.Session["_messages"]) ?? new List<Message>()).Count > 0;
            }
        }

        public static void Add(MessageType type, string message)
        {
            Message m = new Message
            {
                Type = type,
                Text = message
            };
            HttpContext.Current.Session["_messages"] = HttpContext.Current.Session["_messages"] as List<Message> ?? new List<Message>();
            ((IList<Message>)HttpContext.Current.Session["_messages"]).Add(m);
        }

        public enum MessageType
        {
            Info,
            Success,
            Error
        }
        public struct Message
        {
            public MessageType Type;
            public string Text;
        }
    }
}

Однако, когда я пытаюсь использовать их в тесте, онпадает (причина HttpContext. Текущий нулевой).Как я могу заставить это работать как в тестах, так и в самом приложении?Я не против изменить этот класс, чтобы использовать для доступа к сеансу что-то другое, кроме HttpContext.Current, но я хочу, чтобы у него были свойства, как и у него, поэтому он не может принимать объект сеанса в качестве параметра.

Есть идеи, как решить эту проблему?

Ответы [ 3 ]

2 голосов
/ 13 мая 2011

Вам необходимо определить IMessagesProvider и использовать контейнер DI для внедрения реализации IMessagesProvider.В реальном использовании у вас будет реализация, использующая сеанс ASP.Net.В тестовом использовании вы будете в основном издеваться над этим.Кстати, у вас, вероятно, не должно быть статического класса сообщений.Фактически, IMessagesProvider, вероятно, заменит ваш статический класс Messages.

Пример:

public class FooController : Controller
{
    IMessagesProvider _messages;

    public FooController(IMessagesProvider messages)
    {
        // Your DI container will inject the messages provider automatically.
        _messages = messages;
    }

    public ActionResult Index()
    {
        ViewData["messages"] = _messages.GetMessages(Session.SessionId);
        return View();
    }
}

Имейте в виду, это очень простой пример.На самом деле, вам, вероятно, нужен еще один класс - модель, которая управляет представлением.Краткое введение:

public ActionResult Index()
{
    var model = PrepareModel(_messages);
    return View(model);
}

«PrepareModel» - это ваш собственный метод, который создает экземпляр нового класса модели, заполняет его необходимыми данными, а затем отправляет их на просмотр.Типично иметь один класс модели для каждого вида.Например, у вас будут классы моделей, такие как «RegistrationFormModel», «DashboardModel», «ChatModel» и т. Д. Это позволяет также иметь строго типизированные представления (отличная вещь).

0 голосов
/ 13 мая 2011

@ xanadont прав, что вам нужно превратить Messages в нормальный класс. Но (и я знаю, что в некоторых кругах это ересь), нет необходимости в одноразовом интерфейсе и полноценной структуре DI. Просто сделайте методы в вашем классе Messages виртуальными, чтобы вы могли имитировать их в своих юнит-тестах, и используйте инъекцию конструктора:

public class FooController : Controller
{
    Messages _messages;

    // MVC will call this ctor
    public FooController() : this(new Messages())
    {
    }

    // call this ctor in your unit-tests with a mock object, testing subclass, etc.
    public FooController(Messages messages)
    {
        _messages = messages;
    }    
}
0 голосов
/ 13 мая 2011

Вы также можете реализовать фиктивный объект сеанса, который наследуется от HttpSessionStateBase class

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...