Итак, давайте поговорим о TDD - что это такое?

TDD означает Разработка через тестирование, и это процесс проектирования при разработке программного обеспечения. Он основан на повторении очень короткого цикла разработки, а требования превращаются в очень специфические тестовые примеры.

В процессе TDD есть пара шагов:

  1. Напишите модульный тест, который не работает.
  2. Напишите достаточно кода, чтобы пройти тест - на этом этапе нас не волнует хороший код.
  3. Выполните рефакторинг кода из предыдущего шага.

Каковы преимущества такого подхода?

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

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

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

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

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

Прежде чем мы начнем писать TDD.

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

Поэтому я просто объяснил общую идею и преимущества процесса проектирования TDD.

Пришло время написать тесты, давайте сделаем это

Описание и требования

Мы будем использовать C # для написания реализации Stack. Почему С #? Ну, потому что я люблю C #, так почему бы и нет? 😄

Итак, наши требования довольно просты: мы хотим реализовать класс Stack, поэтому требования следующие:

  1. Ограничьте размер стопки.
  2. Добавить элемент. (толкать)
  3. Удалить элемент. (поп)
  4. Проверьте, что было последним элементом. (заглянуть)
  5. Получите текущий размер стека.
  6. Имейте класс, который может принимать любой тип данных.
  7. Когда размер клиента превышает размер стека, нам нужно вызвать соответствующее исключение.

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

Реализация стека в TDD - Построение инфраструктуры

Я использую Visual Studio 2019. В нем я открою новый проект:
Открыть Visual Studio 2019 - ›Создать новый проект -› Поиск консольного приложения (.NET Core).
Выберите название проекта - например, «Стек».

Теперь мы откроем еще один проект только для тестов и назовем его «StackTests».

Откройте обозреватель решений. У нас есть один проект под названием «Стек». Теперь щелкните правой кнопкой мыши «Решение» и выберите Добавить - ›Новый проект и найдите Библиотека классов (.NET Core).

Теперь обозреватель решений проекта должен выглядеть так:

Давайте установим наши модульные тесты: щелкните правой кнопкой мыши проект StackTests, выберите Управление пакетами NuGet, перейдите к «Обзор» и установите следующие пакеты. :

  • NUnit (для этого урока я установил версию 3.12.0)
  • NUnit3TestAdapter (для этого руководства я установил версию 3.17.0)
  • Microsoft.NET.Test.Sdk (для этого руководства я установил версию 16.8.3)

Это установленные пакеты NuGet:

Добавьте новый класс в проект StackTests и назовите его StackTest. Теперь решение должно выглядеть так:

Реализация стека в TDD - Написать код

Мы начнем выписывать тестовые блоки в проекте StackTests в классе StackTest.

Прежде чем мы сможем начать писать код, нам нужно изучить 3 важные вещи: TestFixture, Test и Assert.

TestFixture - это атрибут, который отмечает класс, содержащий тесты и, опционально, методы setup или teardown.

Атрибут Test - это один из способов пометить метод внутри класса TestFixture как тест.

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

Импортируйте «NUnit.Framework» и поместите атрибут [TestFixture] над определением класса.

Тест на создание

Хорошо, пора написать нашу первую функцию. Мы напишем тест создания, который создаст новый объект нашего стека, и он проверит, что размер стека в начале равен 0.

Итак, мы написали наш первый тест, давайте его запустим.

На панели инструментов нажмите Тест - ›Выполнить все тесты.

Если ваш Обозреватель тестов не открыт, нажмите Тест - ›Windows -› Обозреватель тестов, и откроется обозреватель тестов.

Как видите, у нас даже не определен наш класс Stack, поэтому мы получаем ошибку компиляции. Теперь давайте напишем достаточно кода, чтобы пройти тест.

Давайте проведем наш первый тест:

  • Создайте новый класс в проекте стека и назовите его «стек». Сделайте этот класс классом универсального типа (тип T).
  • Мы определили, что этот класс (стек) будет реализован как массив, поэтому мы определим поле-член как массив типа T.
  • Нам необходимо передать в конструктор максимальную длину стека, поэтому мы создадим конструктор, который принимает аргумент размера.
  • А поскольку мы требуем, чтобы в любой момент мы получали текущий размер стека, мы определим свойство «Размер». Конечно, никто не сможет изменить размер, поэтому это будет частный набор.

Теперь давайте снова запустим тесты (проверьте, как запускать тесты выше) и посмотрим результаты.

Итак, мы сделали нашу первую итерацию с дизайном TTD! Теперь нам нужно провести рефакторинг нашего кода, но на данный момент нам действительно нечего рефакторировать, поэтому мы будем двигаться дальше.

Push & Pop тест

Теперь мы хотим протестировать функциональность push и pop, поэтому давайте создадим тестовый пример.

  • Push примет аргумент и добавит его в начало стека.
  • Pop удалит элемент из стека и вернет его.

Мы добавим 3 элемента в стек, затем уберем последний элемент. На этом этапе мы проверим, что последний элемент является именно тем, который мы ожидаем получить, и что размер стека уменьшился.

Как видите, функций push и pop даже не существует, поэтому, когда мы запускаем тесты, мы получаем ошибку в наших результатах . Давайте перейдем к классу Stack и реализуем их.

Давайте снова запустим наши тесты, и бум, все работает отлично! Все тесты прошли успешно 😜

Ошибка превышения допустимого размера

Мы хотим генерировать пользовательские исключения, когда мы:

  1. Подтолкнуть новый элемент, когда стек будет заполнен.
  2. Извлечь элемент, когда в стеке нет элементов.

Итак, как вы уже знаете ... что нам теперь делать?

Верный! Мы определяем тестовые примеры, а затем заставляем код работать.

Как видите, нам нужно создать два новых пользовательских исключения.

  • ExpenditureProhibitedException - это исключение возникает, когда стек пуст и клиент пытается извлечь новый элемент.
  • ExceededSizeException - это исключение возникает, когда стек заполнен и клиент пытается добавить в стек новый элемент.

Перейдите в Проект стека и создайте новый класс с именем CustomExceptions. В этом классе мы определим наши новые исключения, и они будут унаследованы от класса Exception.

Измените наши текущие функции push и pop, чтобы при необходимости генерировать исключение.

Итак, теперь, в рамках жизненного цикла TDD, мы проводим тесты… и ура! Все испытания прошли успешно.

Взгляните на последний элемент

Мы подошли к концу с последними тестами. Мы хотим посмотреть последний элемент в стеке. Если стек пуст, мы выдадим исключение ExpenditureProhibitedException, в противном случае мы вернем последний элемент.

Давайте создадим наши тестовые примеры.

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

Когда мы запускаем тесты, они терпят неудачу - метод peek даже не существует и в нем нет функциональности.

Мы создадим функцию Peek в Stack class.

Теперь, когда мы снова запускаем тесты, мы видим, что все они проходят успешно.

В заключение

Как видите, идея несложная, и есть много инструментов, которые помогают реализовать принципы TDD.

Вы можете просмотреть весь код на моем GitHub.

MosheWorld / Пример разработки через тестирование (github.com)

Мы приветствуем любые комментарии - Если вы обнаружите ошибки в статье, я буду рад, если вы свяжетесь со мной через LinkedIn, и я исправлю ошибки.

Не стесняйтесь обращаться ко мне напрямую в LinkedIn - Щелкните здесь.