Saturday, July 26, 2014

Автоматическое тестирование кода с Code Digger

В этой статье мы с вами поговорим о том, как можно автоматически покрыть тестами код, который мы с вами пишем. Если вы используете в своей практике полноценную разработку через тестирование (англ. Test Driven Development, TDD) то, возможно, эта статья немного расширит ваш кругозор. 
Сегодня мы рассмотрим расширения для Visual Studio под названием Microsoft Code Digger, которое позволяет анализировать выполнение .NET кода, в результате которого строится таблица, где можете посмотреть поведение вашего кода на сгенерированных автоматических аргументах, которые ваш код принимает. Это позволяет отловить явные проблемы с кодом, которые лежат на поверхности и которые вы могли упустить при его написании. 
Я долго размышлял, стоит ли писать данную статью, поскольку активно использую TDD при разработке программного обеспечения (ПО), и этот анализатор пользы мне принес самый минимум. Но посмотрев на это с другой стороны, решил все-таки раскрыть эту тему, так как она вполне может кому-то показаться интересной и повлиять на использование данного анализатора в своих приложениях. Сам анализатор Code Digger использует движок Pex, а также Z3 для анализа всех веток кода, который анализируя эти ветки пытается создать тесты, которые максимально покроют ваш код.
Впервые об автоматической проверке кода с помощью Pex движка я услышал лет эдак 4-5 назад. Тогда он не пользовался особой популярностью, сейчас ситуация в данном случае  кардинально не изменилась. Возможно, проблема в слабой раскрутке или еще в чем-то, но сейчас не так много людей знают об этом, а даже если и знают, то практически не используют. К сожалению, если вы используете студию ниже 2012/2013, вам не доступен Code Digger, но вы можете использовать возможности движка Pex, скачав для этого расширения для версий Visual Studio ниже, чем 2012, например, по ссылке Pex and Moles
Интересный момент заключается также в том, что мы можем пощупать Pex в онлайн-режиме. Для этого можем перейти по ссылке Pex for fun и посмотреть на практике, что у нас получится.
Сам генератор кода постоянно генерирует какой-то свой тестовый пример, который вы можете запустить и посмотреть на результат. Например, после запуска кода, который мне сгенерировал онлайн-генератор и который вы можете посмотреть выше, выдал мне такой результат:
Вы можете написать для теста свой код, главное - не изменять метод Puzzle, поскольку ваш код не будет работать. Вы можете изменить сигнатуру метода, количество параметров, но не изменяйте само имя, иначе у вас не будет работать пример. Вот пример, как я переписал метод Puzzle, для того чтобы рассчитать факториал:
Но только иногда онлайн-редактору для Pex сносило крышу, и я получал такие ошибки:
Если у вас будет что-то не получаться в редакторе, попробуйте открыть онлайн-редактор для Pex по данной ссылке. Но давайте проверим, как это все использовать со студии. Для этого создадим новый консольный проект и назовем его CalculatorSample.
Затем добавим новый класс Calculator и реализуем его следующим образом:
public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public int Substract(int a, int b)
    {
        return a - b;
    }

    public int Multiple(int a, int b)
    {
        return a * b;
    }

    public double Devide(int a, int b)
    {
        return a / (double)b;
    }

    public int Factorial(int a)
    {
        if (a == 0 || a == 1)
            return 1;
        if (a == 2) return a;
        return a*Factorial(a - 1);
    }

    public int Sum(int[] arg)
    {
        return arg.Sum();
    }
}
Код на самом деле очень простой, поэтому, думаю, не нуждается в комментариях. Теперь для того чтобы использовать возможности Code Digger, нам необходимо его настроить. Для этого перейдем в Tools -> Options…
Затем ищем в опциях Pex->General, смотрим в правой части нашего окна настройки для Code Digger и выставляем свойство DisableCodeDiggerPortableClassLibraryRestriction в значение True. Что, собственно, и показано на рисунке выше.
При выборе какого-то метода из нашего класса Calculator у вас станет доступен пункт меню "Generate Inputs / Outputs Table". Ниже приведен пример меню после установки курсора на функцию Factorial.
Если мы выберем этот пункт меню, то сможем увидеть полученный результат в окне "Inputs / Outputs", как показано в результате ниже.
Сразу минусы, которые бросаются в глаза практически любому разработчику: проверка входных аргументов только от 0 до 4-х. В этой функции очень много ошибок. Начиная от самых маленьких (отсутствие отрицательных значений до OverflowException, когда при умножении выйдем за границу Int.MaxValue) до более крупных, как, например, ошибка StackOverflowException из-за рекурсии, которая у нас используется. Если честно, то я ожидал, что с 2010 года, когда я впервые прощупал Pex, они это исправят. Но, как показала практика, ничего особо не изменилось. Давайте выполним следующую проверку для метода Sum класса Calculator.
public int Sum(int[] arg)
{
    return arg.Sum();
}
Результат, в отличие от предыдущей проверки, будет отличаться и иметь ошибочные значения.
Теперь давайте попробуем этот тест исправить, чтобы обрабатывать null и ошибку OverflowException.  Для этого перепишем наш код следующим образом:
public int Sum(int[] arg)
{
    if(arg == null)
        throw new ArgumentNullException("Agument arg can't be null");
    int result = 0;
    checked
    {
        result = arg.Sum();
    }

    return result;
}
Для того чтобы ключевое слово checked у нас заработало, необходимо настроить дополнительные настройки для студии. Для этого нажмем правой клавишей на нашем проекте и выберем пункт меню Properties. Выбираем в табе Build и нажимаем в самом низу кнопку Advanced.
Затем в диалоговом окне Advanced Build Settings устанавливаем галочку Check for arithmetic overflow / underflow.
Затем на нашем методе Sum выберем в выпадающем меню пункт "Generate Inputs / Outputs Table" и повторим генерацию теста для данной функции.
Результат мне очень не понравился. Почему-то Code Digger не обрабатывает нормально checked/unchecked. Сначала я подумал, что, возможно, проблемы в студии и написал простенький пример, чтобы это проверить.
class Program
{
    static void Main(string[] args)
    {
        var calculator = new Calculator();
        calculator.Sum(new[] {-2145112028, -2147483136});
        Console.ReadLine();
    }
}
Но, как оказалось, проблема точно не в студии, так как после запуска приложения я получил следующий результат:
Всякие фреймворки для тестирования, наподобие nUnit, xUnit, MS Test и другие, нормально ловят такие ошибки, а вот Code Digger я так и не смог подружить с ошибками типа OverflowException. Если вы знаете, как это сделать, прошу написать мне в комментариях к статье, так как очень интересно, реально ли это сделать. А пока что это огромный минус в сторону Code Digger.

Итоги

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

No comments:

Post a Comment