Crystal поставляется в комплекте с модулем Spec
, который предоставляет инструменты, необходимые для тестирования вашего кода. Например, предположим, что у вас есть следующий метод, который возвращает сумму двух значений как часть
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
, например --order=random
для crystal spec
. Это запустит все тестовые примеры в случайном порядке, что может помочь выявить случаи, когда одна спецификация требует запуска предыдущей, а это не то, что вам нужно.
Файл crystal init
, используется в качестве точки входа в тесты проекта. Этот файл обычно требует спецификации, исходного кода проекта, а также любых других файлов, специфичных для спецификации, таких как фикстуры или макеты. Здесь также могут быть определены глобальные помощники тестирования. Каждый тест должен требовать, чтобы этот файл имел доступ к модулю Spec
и другим помощникам.
В предыдущем примере мы использовали только утверждение eq
, то есть два значения равны. Однако модуль Spec
предоставляет множество других утверждений, как показано в следующем примере:
require "spec"
it do
true.should be_true
nil.should be_nil
10.should be >= 5
"foo bar baz".should contain "bar"
10.should_not eq 5
expect_raises Exception, "Err" do
raise Exception.new "Err"
end
end
Полный список см. на https://crystal-lang.org/api/Spec/Expectations.html. Этот пример также демонстрирует, что внешний блок #describe не требуется. Однако обычно рекомендуется включить один из них, поскольку он помогает в организации тестов. Однако блок #it
По мере роста количества кода в приложении будет расти и количество тестов. Это может затруднить отладку конкретных тестовых случаев. В этом случае аргумент focus: true
можно добавить в блок #describe
или #it
. При этом будет выполнена только одна спецификация, как в следующем примере:
it "does something", focus: true do
1.should eq 1
end
Только не забудьте удалить его перед совершением!
Модуль Spec
также предоставляет некоторые дополнительные методы, которые можно использовать для более точного контроля выполнения ваших тестовых случаев. Некоторые из них перечислены здесь:
• #pending
: этот метод используется для определения тестового примера для чего-то, что еще не полностью реализовано, но будет реализовано в будущем, например, ожидающий "check cat" { cat.alive? }
. Блок метода никогда не выполняется, но может использоваться для описания того, что должен делать тест.
• #pending!
: Метод #pending!
аналогичен предыдущему методу, но может использоваться для динамического пропуска тестового примера. Это может быть полезно для обеспечения выполнения зависимостей/требований системного уровня перед запуском тестового примера.