RSpec — это мощная среда тестирования для Ruby, которая позволяет разработчикам писать выразительные и удобочитаемые тесты. Одной из ключевых особенностей RSpec является обширная коллекция средств сопоставления, которые используются для определения ожидаемого поведения тестируемого кода. В этой статье мы рассмотрим концепцию расширения средств сопоставления из родительского класса и то, как это может улучшить рабочий процесс тестирования. Итак, приступим!
Расширение средств сопоставления из родительского класса.
В RSpec средства сопоставления определяются как классы Ruby, которые наследуются от базового класса RSpec::Matchers::BuiltIn::BaseMatcher
. Это наследование позволяет создавать собственные сопоставители, расширяя существующие сопоставители или создавая совершенно новые. Расширяя средства сопоставления из родительского класса, вы получаете все возможности родительского средства сопоставления, а также можете добавить свое собственное поведение.
Пример 1. Расширение функции eq
Matcher
Предположим, вам часто приходится проверять равенство с небольшим допуском, например, при сравнении чисел с плавающей запятой. Вместо повторения одного и того же кода снова и снова вы можете создать собственное средство сопоставления, расширяющее встроенное средство сопоставления eq
.
class ApproximateEqMatcher < RSpec::Matchers::BuiltIn::Eq
def initialize(expected, delta)
@expected = expected
@delta = delta
end
def matches?(actual)
(actual - @expected).abs <= @delta
end
def description
"be approximately #{@expected} (±#{@delta})"
end
end
RSpec.describe "ApproximateEqMatcher" do
it "matches floating-point numbers with a tolerance" do
expect(3.14159).to be_approximately_eq(3.14, 0.01)
end
end
В приведенном выше примере мы определили собственное средство сопоставления под названием ApproximateEqMatcher
, которое наследуется от средства сопоставления eq
. Метод matches?
проверяет, находится ли фактическое значение в пределах указанного допуска ожидаемого значения. Метод description
дает четкое описание поведения средства сопоставления.
Пример 2: Расширение функции include
Matcher
Предположим, вам часто нужно проверить, содержит ли коллекция определенный элемент, но вы также хотите убедиться, что этот элемент соответствует определенным условиям. Расширив средство сопоставления include
, вы можете создать собственное средство сопоставления, отвечающее этому требованию.
class CustomIncludeMatcher < RSpec::Matchers::BuiltIn::Include
def initialize(expected, condition)
@expected = expected
@condition = condition
end
def matches?(actual)
super(actual) && actual.any? { |item| @condition.call(item) }
end
def description
"include #{@expected} that satisfies the condition"
end
end
RSpec.describe "CustomIncludeMatcher" do
it "matches collections that include an item satisfying a condition" do
expect([1, 2, 3, 4, 5]).to custom_include(4, ->(item) { item.even? })
end
end
В этом примере мы создали собственное средство сопоставления под названием CustomIncludeMatcher
, которое расширяет средство сопоставления include
. Метод matches?
сначала проверяет, включает ли коллекция ожидаемый элемент, используя реализацию родительского сопоставителя (super(actual)
). Затем он дополнительно проверяет, удовлетворяет ли какой-либо элемент коллекции заданному условию. Метод description
дает четкое описание поведения средства сопоставления.
Расширение средств сопоставления из родительского класса в RSpec позволяет вам использовать существующие функциональные возможности и создавать собственные средства сопоставления, адаптированные к вашим конкретным потребностям тестирования. Используя этот метод, вы сможете писать более выразительные тесты и улучшить читаемость вашей кодовой базы. Используйте возможности унаследованных средств сопоставления в RSpec и поднимите свою игру по тестированию на новый уровень!