Вопрос или проблема
У меня есть следующий метод:
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
, вероятно, вызывается без аргументов, что приводит к ошибке.
Рекомендации по тестированию
-
Использование блока для проверки аргументов:
Как было указано ранее, вы можете использовать блок для более детального контроля переданных аргументов. Пример кода выглядит следующим образом:expect(repository).to receive(:clone) do |**kwargs| expect(kwargs).not_to include(:branch) end
В данном случае
kwargs
является хэшем, содержащим все переданные ключевые аргументы метода. Вы проверяете, что:branch
не включен в этот хэш. -
Краткое объяснение кода:
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
.
-
Тестирование совместно с другими аргументами:
Этот метод позволяет вам не беспокоиться о том, какие другие аргументы передаются в методclone
. Вы можете протестировать вызов, не зная заранее всех возможных значений для других параметров.
Альтернативные подходы
Если вам нужно и дальше поддерживать более чистый синтаксис, вы также можете рассмотреть возможность применения других паттернов проектирования в вашем коде, например использование опциональных хэш-аргументов. Однако, учитывая ваши требования, решение через блок является наиболее практичным и элегантным.
Заключение
Таким образом, чтобы протестировать отсутствие аргумента branch
при вызове метода clone
в Ruby 3.x, вы можете использовать конструкцию с блоком. Несмотря на то, что это может показаться не столь лаконичным по сравнению с единичным матчером, данный подход позволяет точно выразить ваши намерения и эффективно проверить нужные условия без изменения исходного метода.
Если у вас есть дополнительные вопросы или нужны уточнения, охотно помогу!