RSpec 3 and why I `expect(you).to care`

RSpec 3 and why I `expect(you).to care`

Red Dot Ruby Conf 2014 talk about the decisions taken to create RSpec 3

D79fc498d7a5b2ce12180890247476f0?s=128

Jon Rowe

June 27, 2014
Tweet

Transcript

  1. RSPEC 3 AND WHY I expect(you).to care

  2. BEFORE(:TALK)

  3. None
  4. None
  5. None
  6. RSPEC 3 AND WHY I expect(you).to care

  7. SEMANTIC VERSIONING

  8. HISTORY

  9. RSPEC 0.x

  10. RSPEC 1.x

  11. RSPEC 2.x

  12. RSPEC 3.x

  13. I EXPECT(YOU).TO CARE

  14. WHY YOU.SHOULD CARE

  15. class MyCustomObject def fuzzy? true end end ! describe do

    specify do my_model = MyCustomObject.new expect(my_model).to be_fuzzy end end
  16. class MyCustomObject def fuzzy? true end end ! describe do

    specify do my_model = MyCustomObject.new my_model.should be_fuzzy end end
  17. class MyCustomObject def fuzzy? true end end ! describe do

    specify do my_model = MyCustomObject.new expect(my_model).to be_fuzzy end end
  18. describe do specify do expect { fail }.to raise_error !

    x = 1 expect { x += 1 }.to( change { x }.from(1).to(2) ) end end
  19. EXPECT(YOU).TO CARE

  20. obj.should matcher

  21. expect(obj).to matcher

  22. obj.should_receive

  23. expect(obj).to receive

  24. obj.stub(:msg)

  25. allow(obj).to receive

  26. obj.should_receive( some: [vals] )

  27. expect(obj).to( receive_messages(some: [vals]) )

  28. DEPRECATED?

  29. None
  30. None
  31. DEPRECATED?

  32. MONKEY PATCHING

  33. obj.should matcher

  34. class FuzzyProxy < BasicObject def initialize(target) @target = target end

    ! def fuzzy? true end ! def method_missing(*args, &block) @target.__send__(*args, &block) end end
  35. describe FuzzyProxy do ! it 'is fuzzy' do instance =

    FuzzyProxy.new(:some_object) instance.should be_fuzzy end ! end
  36. None
  37. REMOVING MONKEY PATCHING

  38. None
  39. NO MONKEY PATCHING BY DEFAULT

  40. describe "SomeClass" do ! context "in some situation" do !

    it "will do something" do # ... end ! end ! end
  41. RSpec.describe "SomeClass" do ! context "in some situation" do !

    it "will do something" do # ... end ! end ! end
  42. RSpec.configure do |config| ! config.disable_monkey_patching! ! end

  43. FORMATTERS

  44. None
  45. None
  46. MODULARISATION

  47. class CustomFormatter # This registers the notifications this formatter #

    supports, and tells RSpec::Core::Formatters.register self, :example_sta ! def initialize(output) @output = output end ! def example_started(notification) @output << "example: “ @output << notification.example.description end ! end
  48. PHILOSOPHY

  49. its(:thing) { … }

  50. it { should be … }

  51. it { is_expected.to be … }

  52. its(:thing) { … }

  53. require ‘rspec/its' ! describe do ! person = Struct.new(:first, :last)

    do def name [first, last].join(' ') end end ! subject(:bob) { person.new('Bob', 'Jones') } ! its(:name) { is_expected.to eq 'Bob Jones' } ! end
  54. examples$ rspec lies_spec.rb --format doc ! ! name should eq

    "Bob Jones" ! Finished in 0.00094 seconds (files took 0.09512 1 example, 0 failures examples$
  55. require ‘rspec/its' ! describe "#name" do ! person = Struct.new(:first,

    :last) do def name [first, last].join(' ') end end ! it "combines first and last" do bob = person.new('Bob', 'Jones') expect(bob.name).to eq 'Bob Jones' end ! end
  56. examples$ rspec refactor_spec.rb --format doc ! ! name combines first

    and last ! Finished in 0.00084 seconds (files took 0.0084 1 example, 0 failures examples$
  57. VERIFIED DOUBLES

  58. describe "verified doubles" do ! it "does something" do my_obj

    = instance_double( "MyObject", does: "cool things” ) expect(my_obj.does).to eq "cool things" end ! end
  59. describe "verified doubles" do ! class MyObject end ! it

    "does something" do my_obj = instance_double( "MyObject", does: "cool things” ) expect(my_obj.does).to eq "cool things" end end
  60. examples$ rspec verified_doubles_in_situ_spe F ! Failures: ! 1) verified doubles

    does something Failure/Error: my_obj = instance_double("M MyObject does not implement: does # ./verified_doubles_in_situ_spec.rb:7:in ! Finished in 0.00046 seconds (files took 0.07 1 example, 1 failure
  61. describe "verified doubles" do ! class MyObject def does; true;

    end end ! it "does something" do my_obj = instance_double( "MyObject", does: "cool things” ) expect(my_obj.does).to eq "cool things" end end
  62. describe "verified doubles" do ! class MyObject def does; true;

    end end ! it "does something" do my_obj = MyObject.new allow(my_obj).to receive(:other) { "things" } expect(my_obj.other).to eq "things" end end
  63. examples$ rspec verify_partial_doubles_spec. . ! Finished in 0.01582 seconds (files

    took 0.12 1 example, 0 failures
  64. describe "verified doubles" do ! class MyObject def does; true;

    end end ! RSpec.configuration.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end ! it "does something" do my_obj = MyObject.new allow(my_obj).to receive(:other) { "things" } expect(my_obj.other).to eq "things" end end
  65. examples$ rspec verify_partial_doubles_spec. F ! Failures: ! 1) verified doubles

    does something Failure/Error: allow(my_obj).to receive(:o #<MyObject:0x00000101820288> does not implement: other # ./verify_partial_doubles_spec.rb:13:in ! Finished in 0.00562 seconds (files took 0.08 1 example, 1 failure
  66. CLEAN HOUSE

  67. object.stub!

  68. it { stub “something” }

  69. it { mock “something” }

  70. at_least(0).times

  71. not_to raise_error(Specific)

  72. autotest support

  73. textmate formatter

  74. describe do let(:thing) { "happen" } ! before(:all) do thing

    end ! it { } end
  75. examples$ rspec broken_let_spec.rb F ! Failures: ! 1) Failure/Error: thing

    RuntimeError: let declaration `thing` accessed in a `before(:context)` hook at: examples/brok `let` and `subject` declarations are not intended to be called in a `before(:conte hook, as they exist to define state that is reset between each example, while
  76. describe do let(:thing) { "happen" } ! before(:all) do thing

    end ! it { } end
  77. describe do ! before(:all) do allow(Object).to receive(:message) end ! it

    { Object.message } end
  78. examples$ rspec before_all_stubs_broken_spec F ! Failures: ! 1) Failure/Error: allow(Object).to

    receive The use of doubles or partial doubles from rspec-mocks outside of the per-test lifecycle is not supported. # ./before_all_stubs_broken_spec.rb:4:in ! Finished in 0.00504 seconds (files took 0.07 1 example, 1 failure
  79. describe do ! before(:all) do RSpec::Mocks.with_temporary_scope do allow(Object).to receive(:message) end

    end ! it { # Object.message } end
  80. UPGRADING

  81. TRANSPEC

  82. describe do ! subject(:string) { "a string" } ! it

    { should be_a String } its(:length) { should == 8 } ! specify do string.should == "a string" end ! end
  83. examples$ transpec Gathering the spec suite data... ! Converting examples/upgrade_spec.rb

    ! Summary: ! 2 conversions from: it { should ... } to: it { is_expected.to ... } 1 conversion from: obj.should to: expect(obj).to ! 6 conversions, 0 incompletes, 0 warnings, 0
  84. describe do ! subject(:string) { "a string" } ! it

    { is_expected.to be_a String } ! describe '#length' do subject { super().length } it { is_expected.to eq(8) } end ! specify do expect(string).to eq("a string") end ! end
  85. AFTER(:TALK)

  86. THANKS

  87. None
  88. THANKS @JONROWE HTTP://JONROWE.CO.UK