Я хочу проверить наличие многих изменений в модели при отправке формы в спецификации функции. Например, я хочу убедиться, что имя пользователя было изменено с X на Y, и что зашифрованный пароль был изменен на любое значение.
Я знаю, что по этому поводу уже есть несколько вопросов, но я не нашел для себя подходящего ответа. Наиболее точным ответом кажется ChangeMultiple
сопоставление Майкла Джонстона: может ли RSpec ожидать изменения в двух таблицах? . Его обратная сторона заключается в том, что можно проверять только явные изменения от известных значений к известным значениям.
Я создал псевдокод о том, как, по моему мнению, может выглядеть лучший сопоставитель:
expect {
click_button 'Save'
}.to change_multiple { @user.reload }.with_expectations(
name: {from: 'donald', to: 'gustav'},
updated_at: {by: 4},
great_field: {by_at_leaset: 23},
encrypted_password: true, # Must change
created_at: false, # Must not change
some_other_field: nil # Doesn't matter, but want to denote here that this field exists
)
Я также создал базовый скелет ChangeMultiple
сопоставителя следующим образом:
module RSpec
module Matchers
def change_multiple(receiver=nil, message=nil, &block)
BuiltIn::ChangeMultiple.new(receiver, message, &block)
end
module BuiltIn
class ChangeMultiple < Change
def with_expectations(expectations)
# What to do here? How do I add the expectations passed as argument?
end
end
end
end
end
Но теперь я уже получаю эту ошибку:
Failure/Error: expect {
You must pass an argument rather than a block to use the provided matcher (nil), or the matcher must implement `supports_block_expectations?`.
# ./spec/features/user/registration/edit_spec.rb:20:in `block (2 levels) in <top (required)>'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
Любая помощь в создании этого настраиваемого сопоставителя приветствуется.
источник
.and change { @something }.by(0)
.should_not
для всех, кому он нуженЕсли вы хотите проверить, что несколько записей не были изменены, вы можете инвертировать сопоставление, используя
RSpec::Matchers.define_negated_matcher
. Итак, добавляемRSpec::Matchers.define_negated_matcher :not_change, :change
в начало вашего файла (или в ваш
rails_helper.rb
), а затем вы можете связать, используяand
:expect{described_class.reorder}.to not_change{ruleset.reload.position}. and not_change{simple_ruleset.reload.position}
источник
Принятый ответ не является на 100% правильным, поскольку полная поддержка составного сопоставителя
change {}
была добавлена в RSpec версии 3.1.0 . Если вы попытаетесь запустить код, указанный в принятом ответе, с RSpec версии 3.0, вы получите сообщение об ошибке.change {}
Есть два способа использовать составные сопоставители с :def supports_block_expectations?; true; end
вRSpec::Matchers::BuiltIn::Compound
класс, либо исправив его обезьяной, либо напрямую отредактировав локальную копию драгоценного камня. Важное замечание: этот способ не полностью эквивалентен первому,expect {}
блок запускается таким образом несколько раз!Запрос на вытягивание, в котором добавлена полная поддержка функций составных сопоставлений, можно найти здесь .
источник
Ответ BroiSatse - лучший, но если вы используете RSpec 2 (или имеете более сложные сопоставители, например
.should_not
), этот метод также работает:lambda { lambda { lambda { lambda { click_button 'Save' @user.reload }.should change {@user.name}.from('donald').to('gustav') }.should change {@user.updated_at}.by(4) }.should change {@user.great_field}.by_at_least(23) }.should change {@user.encrypted_password}
источник