Освоение RSpec: раскрытие возможностей унаследованных сопоставлений

RSpec — это мощная среда тестирования для Ruby, которая позволяет разработчикам писать выразительные и удобочитаемые тесты. Одной из ключевых особенностей RSpec является обширная коллекция средств сопоставления, которые используются для определения ожидаемого поведения тестируемого кода. В этой статье мы рассмотрим концепцию расширения средств сопоставления из родительского класса и то, как это может улучшить рабочий процесс тестирования. Итак, приступим!

Расширение средств сопоставления из родительского класса.
В RSpec средства сопоставления определяются как классы Ruby, которые наследуются от базового класса RSpec::Matchers::BuiltIn::BaseMatcher. Это наследование позволяет создавать собственные сопоставители, расширяя существующие сопоставители или создавая совершенно новые. Расширяя средства сопоставления из родительского класса, вы получаете все возможности родительского средства сопоставления, а также можете добавить свое собственное поведение.

Пример 1. Расширение функции eqMatcher
Предположим, вам часто приходится проверять равенство с небольшим допуском, например, при сравнении чисел с плавающей запятой. Вместо повторения одного и того же кода снова и снова вы можете создать собственное средство сопоставления, расширяющее встроенное средство сопоставления 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: Расширение функции includeMatcher
Предположим, вам часто нужно проверить, содержит ли коллекция определенный элемент, но вы также хотите убедиться, что этот элемент соответствует определенным условиям. Расширив средство сопоставления 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 и поднимите свою игру по тестированию на новый уровень!