Тестирование метода, который отправляет электронную почту без отправки почты - PullRequest
3 голосов
/ 12 мая 2010

У меня есть метод, подобный

public abstract class Base
{
    public void MethodUnderTest();
}

public class ClassUnderTest : Base
{
    public override MethodUnderTest()
    {
        if(condition)
        {
            IMail mail = new Mail() { /* ... */ };
            IMailer mailer = new Mailer() { /* ... */ }

            mailer.Send(mail);
        }
        else
        {
            /* ... */
        }
    }
}

У меня есть модульные тесты для этого метода, и письмо отправляется самому себе, так что это не страшно (лучше, чем отсутствие теста), но я бы предпочел не отправлять почту.

  • Проблема, с которой я столкнулся, заключается в том, что я не хочу тестировать определенный код в классе (т.е., если (testMode) возвращает; вместо отправки почты)
  • Я не знаю много о DI, но я подумал о том, чтобы передать имитацию IMailer в MethodUnderTest, за исключением того, что он переопределяет базовый класс, и никакой другой класс, производный от Base, не нуждается в объекте IMailer (я не хочу заставлять разработчиков базы, чтобы взять ненужный IMailer в MethodUnderTest)

Что еще я могу сделать?

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

Ответы [ 6 ]

7 голосов
/ 12 мая 2010

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

Если по какой-то причине это нежелательно (это довольно редко, обычно это актуально только в том случае, если вы не управляете базовыми классами), вы можете использовать инъекцию сеттера ("внедрение свойства").

2 голосов
/ 12 мая 2010

Вы можете настроить действительно простой поддельный SMTP-сервер, который знает достаточно, чтобы убедиться, что клиент отправляет электронное письмо.

2 голосов
/ 12 мая 2010

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

http://www.singular.co.nz/blog/archive/2007/11.aspx

http://www.singular.co.nz/blog/archive/2007/12/19/programmatically-setting-the-smtpclient-pickup-directory-location-at-runtime.aspx

http://forum.discountasp.net/showthread.php?t=4593

1 голос
/ 13 мая 2010

Я бы сделал что-то подобное (учитывая, что у вас нет DI-фреймворка):

public class ClassUnderTest : Base
{
    private IMail mail;
    private IMailer mailer

    public ClassUnderTest()
    {
        mail = new Mail() { /* ... */ };
        mailer = new Mailer() { /* ... */ }
    }
    public ClassUnderTest(IMail mail, IMailer mailer)
    {
        this.mail = mail;
        this.mailer = mailer;
    }

    public override MethodUnderTest()
    {
        if(condition)
        {
            mailer.Send(mail);
        }
        else
        {
            /* ... */
        }
    }
}

Затем в своем тесте просто вызовите второй конструктор, а не конструктор по умолчанию.

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

Вы можете перехватить вызов для отправки почты на многих уровнях, но вам все равно придется перехватить его где-то или смириться с получением писем.

Это может быть:

  • мириться с тестовыми письмами.

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

  • Отправьте свои тестовые сообщения на другой адрес электронной почты. Настройте сервер так, чтобы он просто удалял эти письма при получении (или оставлял их на 14 дней, как спам, чтобы вы могли просматривать их, если хотите).

  • Замените ваш почтовый сервер на поддельный локальный

  • Замените класс реализации IMailer imailer.dll или IMailer на полностью смоделированный эквивалент или класс, который не реализует полное поведение SendMail.

  • Добавьте метод базового класса в SendMail () и отключите его поведение в базовом классе при запуске модульного теста.

  • Добавьте виртуальный метод SendMail () в ClassUnderTest, а затем создайте производный класс для модульного тестирования, который просто переопределяет SendMail () с поддельной реализацией.

  • Передайте интерфейс / объект, который он использует для вызова SendMail

  • Передайте флаг, чтобы указать, проверяется ли он.

  • Перепроектируйте класс полностью, чтобы он имел SendReport () и отчет мог быть отправлен по электронной почте, TCP / IP, файлу журнала и т. Д.

  • и т.д.

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

0 голосов
/ 12 мая 2010

Мой ответ в целом (я не знаю C #)

Мне когда-то нужно было сделать что-то подобное в Java. Я сделал тест, чтобы проверить, открывается ли порт отправки, значит, он почти готов. Я вынужден остановить процесс.

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