Написание стандартов для модульного тестирования

Я планирую ввести набор стандартов для написания юнит-тестов в моей команде. Но что включить?

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

Другие домены, которые должны быть охвачены в моих стандартах, должны определять, как создаются тестовые классы и как их организовывать. Например, если у вас есть класс с именем OrderLineProcessor, должен быть тестовый класс с именем OrderLineProcessorTest. Если в этом классе есть метод с именем Process(), то должен быть тест с именем ProcessTest (возможно, больше для проверки различных состояний).

Любые другие вещи, чтобы включить?

Есть ли в вашей компании стандарты для модульного тестирования?

РЕДАКТИРОВАТЬ: я использую Visual Studio Team System 2008 и я развиваю в C#.Net

10 ответов

Решение

Посмотрите на Майкла Фезерса о том, что такое юнит-тест (или что делает юнит-тесты плохими юнит-тестами)

Взгляните на идею "Arrange, Act, Assert", то есть идею, что тест выполняет только три вещи в фиксированном порядке:

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

Взгляните на http://en.wikipedia.org/wiki/Behavior_Driven_Development, чтобы найти способ привести тестовые примеры в соответствие с требованиями.

Кроме того, мое мнение о стандартных документах сегодня заключается в том, что вы не должны писать их, если не обязаны - уже есть много доступных ресурсов. Ссылка на них, а не перефразирование их контента. Предоставить список чтения для разработчиков, которые хотят знать больше.

Возможно, вам стоит взглянуть на серию "Прагматическое модульное тестирование". Это версия C#, но есть и другая для Java.

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

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

Я следую BDD-стилю TDD. Смотрите: http://blog.daveastels.com/files/BDD_Intro.pdf http://dannorth.net/introducing-bdd http://behaviour-driven.org/Introduction

Короче говоря, это означает, что

  • Тесты рассматриваются не как "тесты", а как спецификации поведения системы (далее называемые "спецификации"). Целью спецификаций является не проверка того, что система работает при любых обстоятельствах. Их намерение состоит в том, чтобы определить поведение и управлять дизайном системы.

  • Имена методов спецификации пишутся как полные английские предложения. Например, характеристики мяча могут включать "мяч круглый" и "когда мяч падает на пол, он отскакивает".

  • Не существует обязательного отношения 1:1 между производственными классами и классами спецификаций (и создание метода тестирования для каждого производственного метода было бы безумным). Вместо этого существует отношение 1:1 между поведением системы и спецификациями.

Некоторое время назад я написал учебник по TDD (где вы начинаете писать игру Tetris с использованием предоставленных тестов), в которой этот стиль написания тестов представлен в виде спецификаций. Вы можете скачать его с http://www.orfjackal.net/tdd-tutorial/tdd-tutorial_2008-09-04.zip Инструкции по работе с TDD/BDD по-прежнему отсутствуют в этом руководстве, но пример кода готов, так что вы можете увидеть, как организованы тесты, и написать код, который их проходит.

Вы заметите, что в этом уроке названы производственные классы, такие как Board, Block, Piece и Tetrominoe, которые сосредоточены вокруг концепций игры в тетрис. Но тестовые классы сосредоточены вокруг поведения игры Tetris: FallingBlocksTest, RotatingPiecesOfBlocksTest, RotatingTetrominoesTest, FallingPiecesTest, MovingAFallingPieceTest, RotatingAFallingPieceTest и т. Д.

  1. Старайтесь использовать как можно меньше утверждений assert для каждого метода тестирования. Это гарантирует, что цель теста четко определена.
  2. Я знаю, что это будет спорным, но не тестируются компилятор - время, проведенное тестирование Java Bean аксессоров и мутаторов лучше, потраченное на написание других тестов.
  3. Старайтесь, где это возможно, использовать TDD вместо написания ваших тестов после кода.

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

Я также выступаю за стиль тестирования Arrange-Act-Assert (AAA), так как вы можете сгенерировать довольно полезную документацию из ваших тестов. Это также заставляет вас задуматься о том, какое поведение вы ожидаете из-за стиля именования.

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

TEST( TestThatVariableFooDoesNotOverflowWhenCalledRecursively )
{
/* do test */
}  

Я использую C++, но соглашение об именах можно использовать где угодно.

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

Люди также говорят о рефакторинге кода, чтобы люди понимали, что модульные тесты - это тоже код. Итак, рефакторинг, рефакторинг, рефакторинг.

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

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

Пользователи полнофункциональных IDE обнаружат, что "некоторые из них" имеют достаточно подробную поддержку для создания тестов по определенному шаблону. Учитывая этот класс:

public class MyService {
    public String method1(){
        return "";
    }

    public void method2(){

    }

    public void method3HasAlongName(){

    }
}

Когда я нажимаю ctrl-shift-T в intellij IDEA, я получаю этот тестовый класс после ответа на 1 диалоговое окно:

public class MyServiceTest {
    @Test
    public void testMethod1() {
        // Add your code here
    }

    @Test
    public void testMethod2() {
        // Add your code here
    }

    @Test
    public void testMethod3HasAlongName() {
        // Add your code here
    }
}

Поэтому, возможно, вы захотите внимательно посмотреть на поддержку инструментов, прежде чем писать свои стандарты.

Обязательно включите то, что не является модульным тестом. Смотрите: что не нужно тестировать, когда дело доходит до модульного тестирования?

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

Проверьте это для получения дополнительной информации об этом: Как я могу улучшить свои тесты Junit... особенно второе обновление.

Если вы используете инструменты из семейства Junit (OCunit, SHunit, ...), имена тестов уже следуют некоторым правилам.

Для своих тестов я использую пользовательские теги Doxygen, чтобы собрать их документацию на определенной странице.

Другие вопросы по тегам