Модульное тестирование Application_Start

Я ищу любую информацию (предпочитаю Moq) о том, как провести модульное тестирование метода Application_Start в Global.asax. Я использую ASP.NET MVC и пытаюсь достичь этого неуловимого 100% покрытия кода!

Дело не в том, что я использую MVC. И сказать, что не тестировать Start не нужно, на самом деле тоже не ответ. Что, если бы у меня был другой код? Мне нужно знать, как это проверить.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
16
0
9 503
5

Ответы 5

эта функция вызывается при первом посещении вашего сайта. повторное использование пула приложений приведет к его повторному запуску

В большинстве ситуаций это обработчик событий не имеет кода, так что не тратьте время на поиски бессмысленных цифр!

Я согласен. Нет причин проверять это событие. Если вы выполняете какую-то логику, которую необходимо протестировать, извлеките ее и протестируйте отдельно. Тестировать что-то, что имеет эту зависимость пула приложений, очень непрактично.

Jab 16.12.2008 23:55

В типичном приложении ASP.NET MVC событие Application_Start часто используется для регистрации настраиваемых маршрутов. Вот хороший Почта, объясняющий, как проводить модульное тестирование ваших пользовательских маршрутов.

Модульное тестирование самих настраиваемых маршрутов имеет смысл, но не распространяется на метод Application_Start. Если бы вы могли проверить, что Application_Start настраивает пользовательские маршруты, это было бы (в некоторой степени) интересно, но я не могу придумать способ сделать это.

Klas Mellbourn 02.10.2012 18:00

Если вы хотите протестировать действия такого элемента, основанного на событиях, выделите действия в отдельный тестируемый метод и просто вызовите его из обработчика. Или, как предложил Дарин, проверьте эффекты метода - в этом конкретном случае ваша таблица маршрутизации зарегистрирована правильно.

Кстати, я никогда не достигал 100% охвата нетривиальным приложением ... Обычно мы ориентируемся на 80% как «достаточно хорошо». Некоторые модули можно тестировать на 100%, но многие из них не практичны.

Тестирование эффектов метода, безусловно, было бы хорошей стратегией, но для этого вам все равно придется вызывать метод прямо или косвенно. Если вы этого не сделаете, вы действительно тестируете другую часть приложения (например, конфигурацию маршрута в RouteConfig).

Klas Mellbourn 02.10.2012 18:11

Я нашел, что лучший способ модульного тестирования материала в Global.asax - это убедиться, что все это находится в тестируемом статическом методе.

Затем передайте этому методу все, что ему нужно, из Global.asax.

Так, например, если вы выполняете проверку сеанса при запуске приложения, у вас может быть такой метод:

public static void CheckSession(HttpSessionStateBase session)
{
...
}

Тогда ваше приложение Start будет просто таким:

protected void Application_Start(object sender, EventArgs e)
{
    CheckSession(new HttpSessionStateWrapper(Session));
} 

Этот пример, очевидно, немного глуп, так как вы, вероятно, сделали бы что-то подобное в начале сеанса :) Вы можете передать этому методу все, что ему нужно: запрос, ответ, кеш и т. д.

Тем не менее, это дает понять. Единственный код, который не будет рассмотрен, - это фактический однострочный вызов в Application_Start. Все остальное можно покрыть тестом с использованием Moq следующим образом:

var session = new Moq<HttpSessionStateBase>();
...Set Expectations...
Global.CheckSession(session.Object);
...Do Asserts...

Вы не добьетесь того 100% покрытия кода, которое ищете, но вы будете чертовски близко, и вы бы соответствовали «духу» закона TDD, если бы не совсем его буква :)

Интересная идея, но удалось ли вам заставить ее работать? Если я перенесу содержимое Application_Start в общедоступный статический метод и попытаюсь вызвать его в тесте, при запуске я получу следующую ошибку: «System.InvalidOperationException: этот метод нельзя вызвать на этапе предварительной инициализации приложения»

Klas Mellbourn 02.10.2012 18:05

@KlasMellbourn Да, я действительно это сделал. Похоже, вы пытаетесь пройти реальную сессию раньше времени? Этот метод предполагает, что вы собираетесь имитировать все, что вам нужно, в HttpSessionStateBase и отправлять это на тестирование. Имеет ли это смысл? Если нет, напишите где-нибудь код, и я посмотрю, смогу ли я понять, что вы пытаетесь сделать ...

CubanX 03.10.2012 17:45

метод просто запускает стандартные строки Application_Start в приложении MVC 4: AreaRegistration.RegisterAllAreas (); FilterConfig.RegisterGlobalFilters (GlobalFilters.Filters); RouteConfig.RegisterRoutes (RouteTable.Routes); BundleConfig.RegisterBundles (BundleTable.Bundles);

Klas Mellbourn 03.10.2012 18:56

Некоторым организациям требуются эти бессмысленные числа, и у них возникают проблемы, не связанные с затратами. Для компаний, имеющих дело с простой информацией, «достаточно хорошо» недостаточно. У меня была точно такая же проблема, и, как и Клас Меллборн, мне нужно было достичь 100% (если не выше!) Следующее сработало для меня. Хотя я бы предпочел пометить его как «Исключить из покрытия кода».

public class Global : HttpApplication
{
    public override void Init()
    {
        AreaRegistration.RegisterAllAreas(); //will error out on app_start
        base.Init();
    }

    /// <summary>
    /// Application_Start method.
    /// </summary>
    /// <param name = "sender">The caller</param>
    /// <param name = "e">The event arguments</param>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "KMM: This method is called dynamically by the framework.")]
    protected void Application_Start(object sender, EventArgs e)
    {
        var container = StructureMapRegistry.Initialize();
        GlobalConfiguration.Configuration.DependencyResolver = new StructureMapResolver(container);
        GlobalConfiguration.Configure(WebApiConfig.Register);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
    }
}

Тогда юнит-тест выглядел так:

 public class GlobalTest : Global
    {
        private HttpRequestMessage FakeRequest;

        DateTime? effectiveDate = DateTime.Now.AddYears(-4);
        private string policyNumber = "1234567890";

        [TestMethod]
        public void ApplicationStart()
        {
            var sender = new object();
            var e = new EventArgs();
            try
            {
                Application_Start(sender, e); // this will error b/c not fully loaded yet.
            }
            catch (InvalidOperationException)
            {
                Thread.Sleep(2000); // give the app time to launch

                Application_Start(sender, e);
            }
            Assert.IsTrue(true);
        }
    }

и, наконец, мне нужно было установить флаг в моем WebApiConfig, чтобы маршруты не регистрировались дважды.

 public static class WebApiConfig
    {
        private static bool isRegistered;
        /// <summary>
        /// Registers the configuration.
        /// </summary>
        /// <param name = "config">The Http Configuration.</param>
        public static void Register(HttpConfiguration config)
        {
            if (isRegistered)
            {
                return;
            }
            config.MapHttpAttributeRoutes();

Теперь, прежде чем ненавистники и пуристы начнут отмечать это, задача состоит в том, чтобы протестировать весь код. Лично я терпеть не могу модифицировать код для соответствия тестам. Это не то же самое, что сделать код тестируемым. Добавление флага isRegistered - это пример артефакта, необходимого для поддержки теста, требующего вызова app_start 2x. Это мелочь, и поскольку этот код вызывается только в app_start, я не собираюсь особо суетиться по этому поводу. Мне, безусловно, было бы интересно, что другие сделали в этом отношении.

Кажется, я помню, как у вашего работодателя было много проблем, не связанных с затратами или причинами. (получил свой голос за то, что действительно ответил на вопрос)

Adam Tolley 20.06.2014 19:51

Другие вопросы по теме