Выбрать главу

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

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

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

Существуют различные виды тестирования, каждый из которых преследует свою цель. Некоторые из них включают следующее:

• Модульное тестирование (Unit testing): изолированное тестирование конкретной функции/метода.

• Интеграционное тестирование (Integration testing): тестирование интеграции различных типов вместе, имитация внешних коммуникаций (база данных, внешние API и т. д.).

• Функциональное тестирование (Functional testing): аналогично интеграционному тестированию, но с меньшим количеством насмешек и более конкретными утверждениями, например, конкретное значение, возвращаемое из базы данных, а не просто подтверждение того, что запрос был выполнен.

• Сквозное тестирование (E2E) (End-to-end (E2E) testing): аналогично функциональному тестированию, но обычно включает пользовательский интерфейс (UI) и минимальное количество макетов.

• Тестирование безопасности (Security testing): проверка отсутствия известных недостатков безопасности в коде. Каждый из этих типов тестирования имеет свои плюсы, минусы и цели. Однако мы собираемся в первую очередь сосредоточиться на модульной и интеграционной/функциональной стороне вещей, начиная с модульного тестирования.

Модульное тестирование

Модульное тестирование означает, что вы хотите протестировать определенный метод, будь то на верхнем уровне или как часть объекта, изолированно. Изолированное тестирование является важной частью этого типа тестирования. Это гарантирует, что вы тестируете только ту логику, которую хотите, а не логику ее зависимостей.

Crystal поставляется в комплекте с модулем Spec, который предоставляет инструменты, необходимые для тестирования вашего кода. Например, предположим, что у вас есть следующий метод, который возвращает сумму двух значений как часть add.cr:

def add(value1, value2)

    valuel + value2

end

Соответствующие тесты для этого могут выглядеть так:

require "spec"

require "./add"

describe "#add" do

  it "adds with positive values" do

    add(1, 2).should eq 3

  end

  it "adds with negative values" do

    add(-1, -2).should eq -3

  end

  it "adds with mixed signed values" do

    add(-1, 2).should eq 1

  end

end

Сначала нам нужен модуль Spec, а затем мы используем метод #describe для создания группы связанных тестов — в данном случае всех тех, которые связаны с методом #add. Затем мы используем метод #it для определения конкретных тестовых случаев, в которых мы утверждаем, что он возвращает правильное значение. У нас есть некоторые из них, определенные для примера. В идеале у вас должен быть тестовый пример для каждого потока, через который может пройти код, и обязательно добавлять новые по мере исправления ошибок.

Если вы тестировали этот метод как часть сегмента, вам нужно было бы создать файл в папке spec/ с именем, оканчивающимся на _spec, например spec/add_spec.cr. Обычно тесты следуют тому же организационному стилю, что и исходный код, например, используют те же подпапки и т.п. После этого вы сможете запустить спецификацию Crystal, которая запустит все спецификации, определенные в папке. В противном случае вы также можете запустить этот файл, как и любую другую программу Crystal, если это разовый тест. Также предлагается использовать опцию --order=random для crystal spec. Это запустит все тестовые примеры в случайном порядке, что может помочь выявить случаи, когда одна спецификация требует запуска предыдущей, а это не то, что вам нужно.