Как протестировать вызов метода с ключевыми аргументами, не включая определенный ключевое слово

Вопрос или проблема

У меня есть следующий метод:

def clone(branch: nil, depth: nil)
  ...
end

Для конкретного тестового случая я хочу проверить, что метод вызывается без аргумента branch. В Ruby 2.x следующий тестовый случай работал правильно:

it 'clones the created repository without a branch' do
  expect(repository).to receive(:clone).with(hash_excluding(:branch))
  method_call
end

Однако в Ruby 3.x это перестало работать, потому что:

#<InstanceDouble(Repository) (anonymous)> received :clone with unexpected arguments
  expected: (hash_not_including(:branch=>"anything"))
       got: (no args)

Существует ли способ протестировать это, не меняя метод, чтобы он принимал Options Hash вместо именованных аргументов? Я искал в интернете, но единственное, что я нашел, это кто-то, кто желал иметь keywords_including и keywords_not_including матчеры, но без конкретного ответа.

Перед тем как открыть вопрос в репозитории RSpec на Github, уже существует ли способ провести этот тест?


Примечание: Для этого теста я не хочу явно задавать другие параметры, т.е. не хочу делать это:

expect(repository).to receive(:clone).with(depth: anything)

Я явно хочу проверить отсутствие параметра branch.


Я попытался изменить ожидание следующим образом:

expect(repository).not_to receive(:clone).with(branch: anything)

И это работает, пока метод вызывается только с параметром branch, например:

clone(branch: 'FETCH_HEAD')

Это делает тест неудачным, как и ожидалось, однако, как только добавляется другой параметр:

clone(branch: 'FETCH_HEAD', depth: 1)

Тест проходит, даже несмотря на то, что вызов включает параметр branch.

Я нашел ответ здесь.

Возможный способ сделать это:

expect(repository).to receive(:clone) do |**kwargs|
  expect(kwargs).not_to include(:branch)
end

Хотя это не так аккуратно, как один матчер, но это решает проблему.

Ответ или решение

Чтобы протестировать вызов метода с параметрами ключевых слов без аргумента branch в Ruby при использовании RSpec, необходимо учесть изменения в версии Ruby 3.x. Ниже представлены шаги и рекомендации, которые позволят вам выполнить данное тестирование.

Проблема

Ваша исходная проблема заключается в том, что в Ruby 3.x ожидание вызова метода с помощью expect(repository).to receive(:clone).with(hash_excluding(:branch)) не дает ожидаемого результата, поскольку метод clone, вероятно, вызывается без аргументов, что приводит к ошибке.

Рекомендации по тестированию

  1. Использование блока для проверки аргументов:
    Как было указано ранее, вы можете использовать блок для более детального контроля переданных аргументов. Пример кода выглядит следующим образом:

    expect(repository).to receive(:clone) do |**kwargs|
     expect(kwargs).not_to include(:branch)
    end

    В данном случае kwargs является хэшем, содержащим все переданные ключевые аргументы метода. Вы проверяете, что :branch не включен в этот хэш.

  2. Краткое объяснение кода:

    expect(repository).to receive(:clone) do |**kwargs|
     expect(kwargs).not_to include(:branch)
    end
    method_call
    • expect(repository).to receive(:clone) – здесь вы ожидаете, что метод clone будет вызван на объекте repository.
    • do |**kwargs| – оператор ** позволяет захватывать все именованные аргументы как хэш.
    • expect(kwargs).not_to include(:branch) – здесь происходит проверка на отсутствие ключа :branch.
  3. Тестирование совместно с другими аргументами:
    Этот метод позволяет вам не беспокоиться о том, какие другие аргументы передаются в метод clone. Вы можете протестировать вызов, не зная заранее всех возможных значений для других параметров.

Альтернативные подходы

Если вам нужно и дальше поддерживать более чистый синтаксис, вы также можете рассмотреть возможность применения других паттернов проектирования в вашем коде, например использование опциональных хэш-аргументов. Однако, учитывая ваши требования, решение через блок является наиболее практичным и элегантным.

Заключение

Таким образом, чтобы протестировать отсутствие аргумента branch при вызове метода clone в Ruby 3.x, вы можете использовать конструкцию с блоком. Несмотря на то, что это может показаться не столь лаконичным по сравнению с единичным матчером, данный подход позволяет точно выразить ваши намерения и эффективно проверить нужные условия без изменения исходного метода.

Если у вас есть дополнительные вопросы или нужны уточнения, охотно помогу!

Оцените материал
Добавить комментарий

Капча загружается...