Тестирование устройства Application_Start

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

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

Ответы

Ответ 1

Некоторые организации требуют этих бессмысленных чисел и имеют проблемы, выходящие за рамки стоимости. Для компаний, занимающихся $-ой информацией, "достаточно хорошо" недостаточно. У меня была точно такая же проблема и, как и у Класа Меллборна, нужно дойти до 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);
    }
}

Затем unit test выглядел следующим образом:

 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, я не буду слишком беспокоиться о нем. Меня, конечно, интересовало бы то, что другие сделали в этом отношении.

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

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

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

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

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

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

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

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

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

Ответ 5

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

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