• #fail
: Наконец, этот метод можно использовать для ручного провала тестового примера. Это можно использовать в сочетании с пользовательской условной логикой для создания более сложных утверждений, с которыми не могут справиться встроенные утверждения.
Маркировка (Tagging) тестов
Теги — это способ организовать спецификации в группы, чтобы можно было выполнить их подмножество. Подобно фокусировке спецификации, теги применяются к блокам #describe
или #it
через аргумент tags
следующим образом:
require "spec"
describe "tags" do
it "tag a", tags: "a" do
end
it "tag b", tags: "b" do
end
end
Отсюда вы можете использовать опцию --tag
через crystal spec
, чтобы контролировать, какие из них будут выполняться, как описано здесь:
• --tag 'a' --tag 'b'
будет включать спецификации, отмеченные b
.
• --tag '~a' --tag '~b'
будет включать спецификации, не помеченные знаком b
.
• --tag 'a' --tag '~b'
будет включать спецификации, отмеченные тегом a, но не отмеченные тегом b
.
Последняя команда может выглядеть так: crystal spec --tag 'a'
. Далее мы рассмотрим, как обрабатывать зависимости внутренних объектов путем создания макетов.
Осмеяние (Mocking)
Предыдущий пример с методом #add не имел никаких внешних зависимостей, но помните в NotificationEmitter
типом аргумента конструктора, а не использовали его непосредственно в методе #process
? Тип NotificationEmitter
является зависимостью типа Processor
.
Причина, по которой мы сделали его аргументом конструктора, заключается в том, что он следует нашим принципам проектирования
Давайте посмотрим на упрощенный пример здесь:
module TransformerInterface
abstract def transform(value : String) : String
end
struct ShoutTransformer
include Transformerinterface
def transform(value : String) : String
value.upcase
end
end
class Processor
def initialize(@transformer : Transformerinterface =
ShoutTransformer.new); end
def process(value : String) : String
@transformer.transform value
end
end
puts Processor.new.process "foo"
Здесь у нас есть тип интерфейса Transformer
, который определяет требуемый метод, который должен реализовать каждый преобразователь. У нас есть единственная его реализация, ShoutTransformer
, которая преобразует значение в верхний регистр. Затем у нас есть тип Processor
, который использует тип интерфейса Transformer
как часть своего метода #process
, по умолчанию использующий преобразователь крика. Запуск этой программы приведет к выводу FOO
на ваш терминал.
Поскольку мы хотим протестировать наш тип Processor
изолированно, мы собираемся создать имитацию реализации преобразователя для использования в нашем тесте. Это гарантирует, что мы не тестируем больше, чем требуется. Взгляните на следующий пример:
class MockTransformer
include Transformerinterface
getter transform_arg_value : String? = nil
def transform(value : String) : String
@transform_arg_value = value
end
end
Он реализует тот же API, что и другие, но фактически не преобразует значение, а просто предоставляет его через переменную экземпляра. Затем мы могли бы использовать это в тесте следующим образом, обязательно потребовав также Processor
и MockTransformer
, если они не определены в одном файле:
require "spec"
describe Processor do
describe "#process" do
it "processes" do