# RSpec運作模式 ### gem “rspec” ![](https://i.imgur.com/CRKhZY9.png) ### gem “rspec-rails” ![](https://i.imgur.com/x6WuwfX.png) ## 運作模式 ```ruby= RSpec.describe "calculation" do it "can add numbers" do expect(1 + 1).to eq(2) end end ``` ### describe ```ruby= RSpec.describe "calculation" do ... end ``` describe主要源自於example_group.rb ![](https://i.imgur.com/7P6j7Fe.png) ### it ```ruby= it "can add numbers" do ... end ``` it主要源自於example.rb ```ruby= RSpec.describe "eg1" do it "e1" it "e2" context "eg1_1" do it "e3" end context "eg2_1" do it "e3" end end ``` ![](https://i.imgur.com/MpgIZjd.png) ### hook ```ruby= before {} after {} around { |ex| ex.run} ``` hooks源自於hooks.rb ```ruby= before(:suite) / after(:suite) #只會運行一次 before(:context) / after(:context) #每個example group會運行一次 before / after /arounf #每個example都會運行一次 ``` ### expect & to ```ruby= expect(1 + 1).to eq(2) ``` Expectation來自rspec-expectations ![](https://i.imgur.com/ZQCn78E.png) ![](https://i.imgur.com/p2JVXRH.png) ### match ```ruby= expect(...).to match([ a_kind_of(String), a_hash_including(a: 4) ]) ``` ```ruby= [ “any string”, {a: 4, b: 6.0}, ] ``` ```ruby= class Match < BaseMatcher def match(expected, actual) return true if values_match?( expected, actual) actual.match(expected) end end ``` values_match? ```ruby= def values_match?(expected, actual) expected = with_matchers_cloned(expected) Support::FuzzyMatcher.values_match?( expected, actual) end ``` Support::FuzzyMatcher.values_match? ```ruby= def self.values_match?(e, a) if Hash === a return hashes_match?(e, a) if Hash === e elsif Array === e && Enumerable === a && !(Struct === a) return arrays_match?( e, a) end ``` hashes_match? ```ruby= def self.hashes_match?( expected_hash, actual_hash) return false if expected_hash.size != actual_hash.size expected_hash.all? do |e_k, e_v| actual_value = actual_hash.fetch(e_k) { return false } values_match?(e_v, actual_value) end end ``` #### Array === e arrays_match? ```ruby= def self.arrays_match?( expected_list, actual_list) return false if expected_list.size!=actual_list.size expected_list.zip(actual_list).all? do |expected, actual| values_match?(expected, actual) end end ``` ### 值與屬性 ```ruby= def self.values_match?(expected, actual) ... (the code we saw earlier) return true if expected == actual begin expected === actual rescue ArgumentError # Some objects, like 0-arg lambdas on # 1.9+, raise # ArgumentError for `expected === actual`. false end end ``` 原比對內容 ```ruby= [ “any string”, {a: 4, b: 6.0} ] ``` 做了三件比對:arrays_match? / === / === ### rspec-mocks ```ruby= RSpec.describe "mocking" do it “adds a foo method" do allow(foo).to receive(:bees) expect(foo.bees).to eq(nil) end end ``` ![](https://i.imgur.com/OWXXRzx.png) ![](https://i.imgur.com/TBhp6E3.png) call foo.bee ![](https://i.imgur.com/ic0g5Kn.png) ## RSpec運作流程 ![](https://i.imgur.com/UpZP3Gj.png)