Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduce-my-gem-factory_strategist

Keiko Kaneko
October 22, 2021

 Introduce-my-gem-factory_strategist

https://kaigionrails.org/2021/ の登壇資料です

Keiko Kaneko

October 22, 2021
Tweet

More Decks by Keiko Kaneko

Other Decks in Technology

Transcript

  1. Keiko Kaneko ( @neko314 ) 2021.10.22 (Fri) Kaigi on Rails

    2021 Day1 FactoryBot ͷ build strategy Λ ͍͍ײ͡௚ͯ͘͠ΕΔ gem Λ ࡞ͬͨ࿩
  2. • ͔Ͷ͜ɹ͚͍͜ • GitHub: neko314 / Twitter: neko314_ • Asakusa.rb

    • גࣜձࣾΞϯυύου • ܹਏ͸ϥΠϑϫʔΫ • ۦ͚ग़͠؍Δক ࣗݾ঺հ
  3. FactoryBot ͷ build strategy Λ͍͍ײ ͡௚ͯ͘͠ΕΔ gem Λ࡞ͬͨ࿩ ↓ FactoryBot

    ͷ build strategy Λ͍͍ײ ͡ʹڭ͑ͯ͘ΕΔ gem Λ࡞͍ͬͯΔ࿩
  4. σϞ $ FATORYSTRATEGIST=1 bin/rspec spec/models/user_spec.rb "./spec/models/user_spec.rb:4 create can be replaced

    to build" . Finished in 0.03062 seconds ( fi les took 5.47 seconds to load)1 example, 0 failures
  5. σϞ $ FATORYSTRATEGIST=1 bin/rspec spec/models/user_spec.rb "./spec/models/user_spec.rb:4 create can be replaced

    to build" . Finished in 0.03062 seconds ( fi les took 5.47 seconds to load)1 example, 0 failures
  6. • build strategies • create • build • build_stubbed •

    attributes_for ಈػ - ςετΛ଎͍ͨ͘͠
  7. • build strategies • create • build • build_stubbed •

    attributes_for ಈػ - ςετΛ଎͍ͨ͘͠ ͜ΕΒΛ࢖͍෼͚͍ͨ
  8. 1. create ͍ͯ͠ΔςετΛͦͷ··࣮ߦ͢Δ 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠

    ͯςετΛ࣮ߦ͢Δ 3. ࠷దͳ build strategy ΛબͿ ࣮૷ - ΍Γ͍ͨॲཧ
  9. 1. create ͍ͯ͠ΔςετΛͦͷ··࣮ߦ͢Δ 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠

    ͯςετΛ࣮ߦ͢Δ 3. ࠷దͳ build strategy ΛબͿ ࣮૷ - ΍Γ͍ͨॲཧ
  10. 1. create ͍ͯ͠ΔςετΛͦͷ··࣮ߦ͢Δ 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠

    ͯςετΛ࣮ߦ͢Δ 3. ࠷దͳ build strategy ΛબͿ ࣮૷ - ΍Γ͍ͨॲཧ
  11. • ෳ੡ͨ͠ϑΝΠϧΛॻ͖׵͑ͯςετ͢Δ → 😇ແݶϧʔϓ • DB ࣗମ͔Β INSERT ͞Ε͍ͯΔ͕ SELECT

    ͞ Ε͍ͯͳ͍Ϩίʔυ͕ͳ͍͔Λௐ΂Δ → ΞϓϦέʔγϣϯ͔Βͷૢ࡞͕೉͔ͬͨ͠ ❓DBͷछྨʹ΋ΑΓͦ͏ʁ ࣮૷ - ࠾༻͠ͳ͔ͬͨ͜ͱ
  12. 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠ ͯςετΛ࣮ߦ͢Δ 2.1. ςετίʔυΛมߋͤͣʹ࣮ݱ͢Δ

    ࣮૷ - ΍Γ͍ͨॲཧ alias_method :create, :build alias_method :create, :build_stubbed
  13. 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠ ͯςετΛ࣮ߦ͢Δ 2.1. ςετίʔυΛมߋͤͣʹ࣮ݱ͢Δ

    🙆ʮ࡞Γͳ͕ΒඞཁͳॲཧΛ੔ཧ͍ͯ͘͠ʯ ͕Ͱ͖ͨͷͰΑ͔ͬͨ ࣮૷ - ΍Γ͍ͨॲཧ alias_method :create, :build alias_method :create, :build_stubbed
  14. 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠ ͯςετΛ࣮ߦ͢Δ 2.1. ςετίʔυΛมߋͤͣʹ࣮ݱ͢Δ

    🙅1ͭ1ͭͷݕࠪ͸Ͱ͖ͳ͍ ࣮૷ - ΍Γ͍ͨॲཧ alias_method :create, :build alias_method :create, :build_stubbed
  15. 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠ ͯςετΛ࣮ߦ͢Δ 2.1. ςετίʔυΛมߋͤͣʹ࣮ݱ͢Δ

    2.2. ςετίʔυΛมߋ࣮ͯ͠ݱ͢Δ ࣮૷ - ΍Γ͍ͨॲཧ ҰମͲ͏΍ͬͯ🤔
  16. 2. create ͷՕॴΛ build ΍ build_stubbed ʹͯ͠ ςετΛ࣮ߦ͢Δ 2.1. ςετίʔυΛมߋͤͣʹ࣮ݱ͢Δ

    2.2. ςετίʔυΛมߋ࣮ͯ͠ݱ͢Δ ϝλσʔλͱ͍ͯ࣋ͬͯ͠Δ࣮ߦ͢΂͖ςε τίʔυΛղੳͯ͠ॻ͖׵͑Δ ࣮૷ - ݁࿦
  17. • ͘͢͝γϯϓϧͳςετͰߟ͑Δ͜ͱʹ͢Δ ࣮૷ # sample_app/spec/models/user_spec.rb 1. require 'rails_helper' 2. 3.

    RSpec.describe User, type: :model do 4. it { expect(FactoryBot.create(:user)).to be_valid } 5. end
  18. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end
  19. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end ςετΛ࣮ߦ
  20. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end FactoryBotΛར༻͍ͯ͠Ε͹ create Ͱ example.run build Ͱ example.run build_stubbed Ͱ example.run Ͱςετ͕௨Δ͔Ͳ͏͔Λ͔֬ΊΔ
  21. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end ԿΛ͍ͯ͠Δͷ͔?? 🤔
  22. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end # class RSpec::Core::Example::Procsy def call(*args, &block) @executed = true @proc.call(*args, &block) end alias run call
  23. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end # class RSpec::Core::Example::Procsy def call(*args, &block) @executed = true @proc.call(*args, &block) end alias run call
  24. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end # class RSpec::Core::Example::Procsy def call(*args, &block) @executed = true @proc.call(*args, &block) end alias run call ͜ͷத਎͸?? 🤔
  25. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end example.example.metadata[:block] = > #<Proc:0 x 00007f9db0a06040 /Users/neko314/ sample_app/spec/models/user_spec.rb:4>
  26. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end example.example.metadata[:block] = > #<Proc:0 x 00007f9db0a06040 /Users/neko314/ sample_app/spec/models/user_spec.rb:4> # sample_app/spec/models/user_spec.rb 1. require 'rails_helper' 2. 3. RSpec.describe User, type: :model do 4. it { expect(FactoryBot.create(:user)).to be_valid } 5. end
  27. ࣮૷ - Ξϓϩʔν 1. RSpec.conf i gure do |conf i

    g| 2. conf i g.around(:example) do |example| 3. example.run 4. end 5. end example.example.metadata[:block] = > #<Proc:0 x 00007f9db0a06040 /Users/neko314/ sample_app/spec/models/user_spec.rb:4> # sample_app/spec/models/user_spec.rb 1. require 'rails_helper' 2. 3. RSpec.describe User, type: :model do 4. it { expect(FactoryBot.create(:user)).to be_valid } 5. end
  28. ΍Γ͍ͨ͜ͱΛ֬ೝ ࣮૷ # sample_app/spec/models/user_spec.rb 1. require 'rails_helper' 2. 3. RSpec.describe

    User, type: :model do 4. it { expect(FactoryBot.create(:user)).to be_valid } 5. end
  29. ΍Γ͍ͨ͜ͱΛ֬ೝ ࣮૷ # sample_app/spec/models/user_spec.rb 1. require 'rails_helper' 2. 3. RSpec.describe

    User, type: :model do 4. it { expect(FactoryBot.create(:user)).to be_valid } 5. end build ΍ build_stubbed ʹ͍ͨ͠
  30. ΍Γ͍ͨ͜ͱΛ֬ೝ ࣮૷ # sample_app/spec/models/user_spec.rb 1. require 'rails_helper' 2. 3. RSpec.describe

    User, type: :model do 4. it { expect(FactoryBot.create(:user)).to be_valid } 5. end ·ͣ build ʹ͢Δ͜ͱΛߟ͑Δ
  31. ࣮૷ example.example.metadata[:block].to_s # = > "#<Proc:0 x 00007fc6b29ae090 /Users/neko314/ sample_app/spec/models/user_spec.rb:4>"

    ϝλσʔλͷ Proc ΦϒδΣΫτ ఆٛ͞Ε͍ͯΔखଓ͖ͷจࣈྻ to_s ΍ inspect ͯ͠ΈΔ
  32. ࣮૷ example.example.metadata[:block].to_s # = > "#<Proc:0 x 00007fc6b29ae090 /Users/neko314/ sample_app/spec/models/user_spec.rb:4>"

    ϝλσʔλͷ Proc ΦϒδΣΫτ ఆٛ͞Ε͍ͯΔखଓ͖ͷจࣈྻ to_s ΍ inspect ͯ͠ΈΔ 😇
  33. ࣮૷ RubyVM : : AbstractSyntaxTree.of(example.example.metadata[:bl ock]) # = > #<RubyVM

    : : AbstractSyntaxTree : : Node:SCOPE@4 : 5-4 : 53> ϝλσʔλͷ Proc ΦϒδΣΫτ ఆٛ͞Ε͍ͯΔखଓ͖ͷจࣈྻ ASTΛऔಘͯ͠ΈΔ
  34. ࣮૷ RubyVM : : AbstractSyntaxTree.of(example.example.metadata[:bl ock]) # = > #<RubyVM

    : : AbstractSyntaxTree : : Node:SCOPE@4 : 5-4 : 53> ϝλσʔλͷ Proc ΦϒδΣΫτ ఆٛ͞Ε͍ͯΔखଓ͖ͷจࣈྻ ASTΛऔಘͯ͠ΈΔ 😇Ճ޻ʹࣦഊͯ͠அ೦
  35. ࣮૷ module ProcParser ref i ne Proc do def body

    # RubyVM : : InstructionSequence ͰऔಘͰ͖Δ γʔέϯεΛ΋ͱʹ spec ϑΝΠϧ͔ΒจࣈྻΛऔಘ end end end ϝλσʔλͷ Proc ΦϒδΣΫτ ఆٛ͞Ε͍ͯΔखଓ͖ͷจࣈྻ
  36. ࣮૷ example.example.metadata[:block].body # = > " expect(FactoryBot.create(:user)).to be_valid " ϝλσʔλͷ

    Proc ΦϒδΣΫτ ఆٛ͞Ε͍ͯΔखଓ͖ͷจࣈྻ 🎉🎉🎉🎉🎉🎉
  37. ࣮૷ new_body = "Proc.new { " expect(FactoryBot.build(:user)).to be_valid\n" }" eval(new_body)

    Ճ޻ͨ͠จࣈྻ จࣈྻ͔Βੜ੒ͨ͠ Proc ΦϒδΣΫτ " expect(FactoryBot.build(:user)).to be_valid\n"
  38. ࣮૷ new_body = "Proc.new { " expect(FactoryBot.build(:user)).to be_valid\n" }" eval(new_body)

    Ճ޻ͨ͠จࣈྻ จࣈྻ͔Βੜ੒ͨ͠ Proc ΦϒδΣΫτ " expect(FactoryBot.build(:user)).to be_valid\n" #<Proc:0 x 00007fa08a88cf70 (eval) : 1>
  39. ࣮૷ new_example = eval(new_body) # = > #<Proc:0 x 00007fa08a88cf70

    (eval) : 1> จࣈྻ͔Βੜ੒ͨ͠ Proc ΦϒδΣΫτ ࣮ߦ݁Ռ
  40. ࣮૷ new_example = eval(new_body) # = > #<Proc:0 x 00007fa08a88cf70

    (eval) : 1> จࣈྻ͔Βੜ੒ͨ͠ Proc ΦϒδΣΫτ ࣮ߦ݁Ռ run_successfully?(new_example) True / False
  41. 1. create ͍ͯ͠ΔςετΛͦͷ··࣮ߦ͢Δ 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠

    ͯςετΛ࣮ߦ͢Δ 3. ࠷దͳ build strategy ΛબͿ ࣮૷ - ΍Γ͍ͨॲཧ
  42. 1. create ͍ͯ͠ΔςετΛͦͷ··࣮ߦ͢Δ 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠

    ͯςετΛ࣮ߦ͢Δ 3. ࠷దͳ build strategy ΛબͿ ࣮૷ - ΍Γ͍ͨॲཧ
  43. 1. create ͍ͯ͠ΔςετΛͦͷ··࣮ߦ͢Δ 2. create ͷՕॴΛ build ΍ build_stubbed ʹ͠

    ͯςετΛ࣮ߦ͢Δ 3. ࠷దͳ build strategy ΛબͿ 3.1. ϝοηʔδΛग़ྗ ࣮૷ - ΍Γ͍ͨॲཧ
  44. ࣮૷ ࣮ߦ݁Ռ build strategy ςετ͕௨Βͳ͍ - build Ͱύε build build_stubbed

    Ͱύε build_stubbed create Ͱύε create build strategyͷબͼํ
  45. ੒Ռ $ FATORYSTRATEGIST=1 bin/rspec spec/models/user_spec.rb "./spec/models/user_spec.rb:4 create can be replaced

    to build" . Finished in 0.03062 seconds ( fi les took 5.47 seconds to load)1 example, 0 failures
  46. ੒Ռ $ FATORYSTRATEGIST=1 bin/rspec spec/models/user_spec.rb "./spec/models/user_spec.rb:4 create can be replaced

    to build" . Finished in 0.03062 seconds ( fi les took 5.47 seconds to load)1 example, 0 failures
  47. ੒Ռ $ FATORYSTRATEGIST=1 bin/rspec spec/models/user_spec.rb "./spec/models/user_spec.rb:4 create can be replaced

    to build" . Finished in 0.03062 seconds ( fi les took 5.47 seconds to load)1 example, 0 failures 🎉🎉🎉🎉🎉🎉
  48. • ࡶͳ gsub Λ΍Ίͯʮ1ͭ1ͭͷ create ΛνΣο Ϋ͢ΔʯΛ࣮ݱ͍ͨ͠ • ΑΓෳࡶͳςετίʔυʹରԠ͍ͨ͠ •

    ग़ྗϝοηʔδΛΘ͔Γ΍͍ͨ͘͢͠ • ଞͷςετϑϨʔϜϫʔΫͰ΋࢖͑ΔΑ͏ʹͨ͠ ͍ ͜Ε͔Β΍Γ͍ͨ͜ͱ