TDD с использованием SharpDevelop на C#

Вторник, 8 мая 2007 (16:31:19)

 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 (Нет голосов)
Loading ... Loading ...

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

Я выбрал бесплатную IDE для .NET SharpDevelop лишь потому, что кроме интегрированной поддержки Subversion и NDoc, он включает в себя также интегрированную поддержку NUnit и NCover, а так же Microsoft FXCop.

Немного теории

Смысл разработки основанной на тестировании (TDD, test-driven development) состоит в том, чтобы сформулировать требования к будущему коду при помощи набора тестов. Набор тестов для отдельно взятого фрагмента кода должен быть написан раньше, чем сам код. Рекомендую для разнообразия также ознакомиться с отличным примером использования TTD на языке Perl.

Постановка задачи

Для начала сформулируем простую задачу. Допустим, у нас имеется класс Email такого вида:

class Email
{
    private string email;
    public string Value
    {
        get {return email;}
        set {email = value;}
    }
}

Вам необходимо написать для него функцию isValid(), которая проверяет правильность адреса электронной почты, и в зависимости от результата проверки, возвращает true или false.

Итерация №1: Болванка

Напишем тест, который будет проверять работу этой функции:

[Test]
public void ValidEmailTest()
{
    Email email = new Email();
    email.Value = "s_tretyak-1979@yandex.ru";
    Assert.AreEqual(true,email.isValid());
}

Этот тест проверяет возвращает ли функция isValid() логическую истину, если объект класса Email содержит правильно сформированный адрес s_tretyak-1979@yandex.ru. Естественно, тест не только не будет пройден, но и проект не будет собран, потому что функция isValid() отсутствует в классе Email. Добавим эту функцию в исходник класса, таким образом, чтобы она удовлетворяла условиям тестового случая:

public bool isValid()
{
    return true;
}

Теперь, если вы запустите тестирование, то увидите, что случай ValidEmailTest() будет пройден.

Итерация №2: Вечерний Дели

Пришло время проверить заведомо неправильный адрес электронной почты. Создадим тестовый случай в котором будет отражено это условие:

[Test]
public void InvalidEmailTest()
{
    Email email = new Email();
    email.Value = "v_petrov-1969.yandex.ru";
    Assert.AreEqual(false,email.isValid());
}

Функция isValid() должна вернуть логическую ложь, поскольку адрес электронной почты сформирован неправильно. В данном случае, в нём отсутствует @. Естественно, этот тест будет провален:

expected: <False> but was: <True>

На этом этапе мы должны модифицировать isValid() таким образом, чтобы она удовлетворяла тестовому случаю, описанному в InvalidEmailTest(). Собственно говоря, поэтому эта техника называется TTD. Решаем задачу «в лоб»:

public bool isValid()
{
    if(email.LastIndexOf('@') != -1)
    return true;
    else return false;
}

Итерация №3: Оно шевелится!

Два теста пройдены, и мы получили некрасивый, но вполне работоспособный код в духе индийского экстремального программирования. Однако, очевидно, что если адрес будет содержать, например, два знака @, то функция isValid() вернёт неверное значение. Для проверки создадим третий тестовый случай:

[Test]
public void InvalidEmailDoubleAtTest()
{
    Email email = new Email();
    email.Value = "i_ivanov-1985@li@ru";
    Assert.AreEqual(false,email.isValid());
}

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

public bool isValid()
{
    Regex myReg = new Regex("^[\\w-\\.]+@\\w+\\.\\w+$");
    return myReg.IsMatch(email);
}

Вместо заключения

По-научному наши телодвижения с функцией isValid() называются «рефакторинг». Смысл в этом такой: как бы мы не изменяли реализацию функции, тесты должны работать. Естественно, нет предела совершенству, и мы можем написать тестовый случай в котором будет ещё проверяться принадлежит ли домен хоста к допустимому TLD и т.п.

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

Запуск юнит-тестирования с анализом покрытия кода

мы увидим те места в нашем коде, которые не покрыты тестами:

Покрытие кода подсвечивается в редакторе IDE SharpDevelop

а так же цифры, которые показывают как покрыт код тестами:

Процент покрытия кода юнит-тестами

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

купить землю: купить землю тут - на странице
холодильная установка: холодильная установка у нас - обсуждение
Статья: Как увеличить эффект с рейтингов оптимизация заголовков

Оставьте сообщение:

Или используйте свой OpenID: