2009-10-14 2 views
0

Я хочу, чтобы мое приложение ловило исключения и отправляло их по электронной почте при запуске в процессе производства, но когда я запускаю свои модульные тесты MSTest, я хочу, чтобы он выдавал исключения, поэтому я могу отлаживать. Мой текущий код всегда отправляет электронные сообщения об исключениях. Есть ли способ узнать, был ли текущий процесс вызван модульными тестами?Есть ли способ определить, является ли это тестом или нет (.NET)?

Один из способов, который я могу представить, - проверить среду Enviroment.CurrentDirectory и аналогичные переменные. Есть лучший?

ответ

2

Это классический вариант использования для инъекции зависимостей или локатора обслуживания. Вместо того чтобы подключить ваше приложение к отправке писем, попросите приложение получить службу уведомлений от локатора службы и попросите его позвонить. В процессе производства настройте локатор службы, чтобы вернуть службу отправки электронной почты; в тестовой среде настройте его, чтобы вернуть службу, которая ничего не делает, или добавить уведомление в список или что-то еще.

Вам не нужно искать полную инъекцию зависимостей: здесь очень простой сервисный локатор. Точно так же инъекция услуги тестового уведомления может быть выполнена с помощью тестового документа. Вот очень простой пример:

public static class ServiceLocator 
{ 
    private static INotificationService _notificationService = new EmailNotificationService(); 

    public static INotificationService NotificationService 
    { 
    get { return _notificationService; } 
    } 

    // For test use only 
    public static void SetNotificationService(INotificationService notificationService) 
    { 
    _notificationService = notificationService; 
    } 
} 

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

Затем в тестовом коде:.

[SetUp] 
public void Setup() 
{ 
    ServiceLocator.NotificationService = new DiscardingService(); 
} 

(Использование NUnit терминологии здесь для метода, запускаемых перед каждым испытанием - не уверен, что эквивалентно MSTest есть)

Преимущество этого заключается в том, что теперь вы можете проверить, что отправляются правильные уведомления: у вас есть служба тестовых уведомлений, которые фиксируют уведомления в списке, и вы можете сделать утверждения об этом списке, чтобы проверить, отправляются ли уведомления и верный.

Снова обратите внимание, что это не полное объяснение DI или сервисных локаторов, и мой примерный код отнюдь не лучший способ сделать это.

+0

Сервисные локаторы действительно являются хорошим решением. –

+3

krystan: Мне они не нравятся, поскольку они скрывают зависимости и загрязняют код приложения с помощью вызовов «получить эту услугу, установить эту услугу». Конструкторский DI означает, что приложение даже не будет построено, если зависимости не будут выполнены. С DI, легко смотреть на любой фрагмент кода изолированно и рассуждать о его зависимостях. –

+0

Оценка: справедливая точка. Причина, по которой я не обсуждал DI подробно, заключается в том, что для этого требуется гораздо больше объяснений, чем упрощенный подход к локальному сервису, а DI на основе конструктора, вероятно, потребует значительно более рефакторинга исходного приложения плаката, чем локатор сервисов. Но, безусловно, существует вероятность того, что правильный DI, скорее всего, будет более ремонтоприемным, поскольку сценарий станет более сложным. – itowlson

1

Вы можете использовать директивы компиляции (например, #IF DEBUG) для выполнения части кода при тестировании и другого кода, скомпилированного в выпущенном режиме;

Другой подход может быть написан другим TraceListeners, поэтому вы можете регистрировать свои исключения в виде обычного текста или отправлять электронную почту, просто настроив файл .config.

+0

Масса, valeu pela dica –

+0

@Jader: é curintia –

+0

Этот подход излишне загромождает код. Лучшая практика заключается в том, чтобы высмеять отправителя электронной почты. Вы можете узнать больше на http://en.wikipedia.org/wiki/Mock_object – Vitaliy

3

Вы также можете установить флажок в приложении App.Config для процедуры электронной почты, чтобы проверить, следует ли отправлять эти сообщения электронной почты, а в вашем тестовом наборе этот флаг установлен на false.

+0

Да, но мой тестовый пример app.config - это нежная ссылка на мое приложение app.config. Мне пришлось бы его дублировать =) Не проблема. –

+0

Só dá Brasil nessa thread –

0

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

.. 
.. 
catch(Exception e) 
{ 
    EmailSender.Send(e); 
} 

Хороший тест блок должен быть изолирован, а это означает, что выполнение код должен граница не Поперечный класс, не говоря уже о отправке сообщения другим процессам!

Предлагаю вам ознакомиться с материалами о насмешливых и насмешливых фреймворках в сети. Я лично использую рамки RhinoMock.

1

Вы можете сделать что-то ДЕЙСТВИТЕЛЬНО ЗЛО, как использовать log4net, а также флаг IsDebug. это, конечно, безумие.

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

Есть несколько хороших рамок для этого

Moq Rhino издевается

эти мои два фаворита.

Когда я говорю о инъекции я имею в виду что-то вроде этого

public class Foo 
{ 
    private Emailer _emailer; 

    public Foo(Emailer mailer) 
    { 
     _emailer = mailer; 
    } 

    public void SomeMethod() 
    { 
     ... 
     try 
     { 
      ... 
     } 
     catch(SomeException ex) 
     { 
      _emailer.SendEmail(ex); 
     } 
     finally 
     {} 
    } 
} 

Каркасов в основном позволяют Вам при определенных условиях переходить в объекте, который в основном подделки, вы можете speicify поведение этих объектов и использовать утверждение и т. д. в nunit.

Но, чтобы ответить на ваш вопрос напрямую, вы МОЖЕТЕ использовать флаг в вашем файле конфигурации, но это не так аккуратно или полезно.

0

Это поможет, если вы расскажете больше о своем конкретном сценарии.

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

Звучит так, как будто вы пытаетесь взломать что-то, что неправильно настроено. Если проблема некритическая, и это безопасно для продолжения, то вы, вероятно, должны просто использовать регистратор, а затем соответствующим образом реагировать на ошибку. Вероятно, есть приложение log4net, которое отправляет электронные письма, если вам все еще нужны эти функции (и если вы не настроите log4net, это ничего не сделает, поэтому ваши тесты не будут отправлять какие-либо письма).

Это не влияет на тестируемость, поскольку вы можете подать условие ошибки, а затем проверить, был ли получен соответствующий ответ (например, «если я не могу прочитать файл конфигурации, а затем вернуть значения по умолчанию»).

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

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

0

Быстрый способ может быть ...

public static class Tester 
{ 
    public static bool InUnitTest 
    { 
     get 
     { 
      return Environment.StackTrace.IndexOf("Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestRunner") > 0; 
     } 
    } 
} 

Затем в приложении вы можете просто

catch (Exception e) 
{ 
    if (!Tester.InUnitTest) 
    { 
     ... // send mail 
    } 
} 

Вы также можете осуществить это в любом классе EmailSender вы можете использовать так что вам не нужно беспокоиться об изменении каждого блока поймать

+0

Я бы не поместил свой код с чем-то вроде этого. Используйте файлы конфигурации для определения, отправлять ли электронную почту или нет. – Fadeproof

Смежные вопросы