RSpec: कई बदलने की उम्मीद है


86

मैं एक मॉडल में कई बदलावों की जांच करना चाहता हूं जब एक फीचर कल्पना में एक फॉर्म सबमिट करना। उदाहरण के लिए, मैं यह सुनिश्चित करना चाहता हूं कि उपयोगकर्ता नाम को 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'

इस कस्टम मिलान बनाने में किसी भी मदद की बहुत सराहना की जाती है।

जवाबों:


183

RSpec 3 में आप एक साथ कई स्थितियाँ सेट कर सकते हैं (इसलिए एकल अपेक्षा नियम नहीं तोड़ा जाता है)। यह sth की तरह दिखेगा:

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अभी तक कोई आसान तरीका नहीं है। मैं आपके अंतिम चेक के बारे में भी अनिश्चित हूँ (यदि यह कोई फर्क नहीं पड़ता, तो इसका परीक्षण क्यों करें?)। स्वाभाविक रूप से आपको इसे अपने कस्टम मैचर के भीतर लपेटने में सक्षम होना चाहिए ।


6
अगर आप यह उम्मीद करना चाहते हैं कि कई चीजें बदली नहीं हैं , तो बस का उपयोग करें.and change { @something }.by(0)
स्टीवेंसियल

1
क्या आप सभी कोष्ठकों के साथ एक दूसरा उदाहरण जोड़ सकते हैं? मुझे यह समझने में मुश्किल है कि कौन से तरीके जंजीर हैं
सिरिल डचोन-डोरिस

मेरा जवाब रूबी 2 के लिए काम करता है और .should_notकिसी के लिए भी काम करता है जिसे इसकी आवश्यकता है
ज़ैक मॉरिस

37

यदि आप परीक्षण करना चाहते हैं कि कई रिकॉर्ड नहीं बदले गए हैं, तो आप एक मिलानकर्ता का उपयोग करके उल्टा कर सकते हैं 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; endमें जोड़ना होगा RSpec::Matchers::BuiltIn::Compound, या तो बंदर को पैच करके या सीधे मणि की स्थानीय प्रति को संपादित करके। एक महत्वपूर्ण नोट: यह तरीका पहले वाले के बराबर नहीं है, expect {}ब्लॉक इस तरह से कई बार चलता है!

कंपाउंड मैचर्स फंक्शनलिटी का पूरा सपोर्ट जोड़ने वाला पुल अनुरोध यहां पाया जा सकता है


2

ब्रायसैट का उत्तर सबसे अच्छा है, लेकिन अगर आप 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
आह, अच्छा विचार है! आप शायद इसे पढ़ने में थोड़ा आसान बनाने के लिए एक रैपर का निर्माण कर सकते हैं!
ब्रूसैटस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.