RSpec : 다중 변경 예상


86

기능 사양에서 양식을 제출할 때 모델의 많은 변경 사항을 확인하고 싶습니다. 예를 들어 사용자 이름이 X에서 Y로 변경되었고 암호화 된 암호가 임의의 값으로 변경되었는지 확인하고 싶습니다.

이미 그것에 대한 몇 가지 질문이 있다는 것을 알고 있지만 나에게 적합한 답을 찾지 못했습니다. 가장 정확한 대답은 ChangeMultipleMichael Johnston 의 matcher 처럼 보입니다 . 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다음과 같이 matcher 의 기본 골격을 만들었습니다 .

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'

이 맞춤 매처를 만드는 데 도움을 주시면 대단히 감사하겠습니다.

답변:


191

RSpec 3에서는 한 번에 여러 조건을 설정할 수 있습니다 (따라서 단일 기대 규칙이 깨지지 않습니다). 다음과 같이 보일 것입니다.

expect {
  click_button 'Save'
  @user.reload
}.to change { @user.name }.from('donald').to('gustav')
 .and change { @user.updated_at }.by(4)
 .and change { @user.great_field }.by_at_least(23}
 .and change { @user.encrypted_password }

그래도 완전한 해결책은 아닙니다. 내 연구가 진행되는 한 and_not아직 쉬운 방법이 없습니다 . 마지막 수표도 확실하지 않습니다 (중요하지 않은 경우 왜 테스트합니까?). 당연히 사용자 정의 매처 내에서 래핑 할 수 있어야합니다 .


7
여러 가지 것을 기대하고 싶은 경우 하지 변경, 단순히 사용.and change { @something }.by(0)
stevenspiel

1
모든 괄호를 사용하여 두 번째 예를 추가 할 수 있습니까? 나는 체인하는 방법을 이해하기 어렵다
시릴 Duchon - 도리스

내 대답은 루비 2 작품과 함께 작동하도록 보인다 .should_not그것을 필요로 누구나
잭 모리스

39

여러 레코드가 변경되지 않았는지 테스트하려면을 사용하여 매처를 반전 할 수 있습니다 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}

2

RSpec 버전 3.1.0 에 대한 전체 복합 매처 지원 change {}이 추가되었으므로 허용되는 대답은 100 % 정확하지 않습니다 . RSpec 버전 3.0에서 허용 된 답변에 제공된 코드를 실행하려고하면 오류가 발생합니다.

와 함께 복합 매처를 사용하려면 change {}두 가지 방법이 있습니다.

  • 첫 번째는 RSpec 버전 3.1.0 이상이어야한다는 것 입니다.
  • 두 번째는 당신이 추가 할 필요가있다 def supports_block_expectations?; true; endRSpec::Matchers::BuiltIn::Compound하나를 패치하거나 직접 보석의 로컬 복사본을 편집 원숭이에 의해, 클래스입니다. 중요한 참고 사항 : 이 방법은 첫 번째 방법과 완전히 동일하지 않으며 expect {}블록은 이런 식으로 여러 번 실행됩니다!

복합 매처 기능에 대한 완전한 지원을 추가 한 풀 요청은 여기 에서 찾을 수 있습니다 .


2

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}

1
아, 좋은 생각이야! 쉽게 읽을 수 있도록 래퍼를 만들 수 있습니다!
BroiSatse
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.