BDD / TDD-マッチャーを書くことを学ぶ

動作仕様開発(BDD)は、Rubyの哲学の基礎の1つです。



BDDの非常に成功した実装は、おなじみのRSpecです。 RSpecの優れた点の1つは、その拡張性です。



そのため、RSpecをFactory GirlMachinistに切り替える価値はありますが)、 RR (スタブの優れたフレームワーク)、 Sporkとともに使用し 、最近はShouldaからRemarkableに切り替えました。



当然、すぐに仕様を理解しやすくしたかったのです。 たとえば、 コールバック定義の仕様をチェックインします



これを行う良い方法は、新しい「マッチャー」を作成することです。







主なロジックはis_valid?メソッドで、テスト対象をチェックして期待どおりかどうかを確認します。



  1. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  2. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  3. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  4. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  5. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  6. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  7. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  8. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  9. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  10. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  11. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  12. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  13. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  14. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  15. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  16. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  17. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  18. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  19. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  20. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  21. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  22. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  23. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )



  24. module Scalaxy module Matchers class CallbackPresenceMatcher < Remarkable::Base arguments :chain , :callback assertion :is_valid ? protected def is_valid? instance = @subject . kind_of ? ( Class ) ? @subject . new : @subject chain_name = "#{@chain}_callback_chain" . to_sym return false unless instance. kind_of ? ( ActiveSupport::Callbacks ) return false unless instance. class . respond_to ? ( @chain ) return false unless instance. class . respond_to ? ( chain_name ) return false if instance. class . send ( chain_name ) . select { | c | c. method == @callback } . empty ? true end end # Matches for presence of specified callback inside specified callback chain. # should_callback_presence :after_run, :notify_people def callback_presence ( * args ) CallbackPresenceMatcher. new ( * args ) . spec ( self ) end end end Remarkable. include_matchers ! ( Scalaxy, ActiveSupport::TestCase )







また、「期待」に関する情報を追加して、ロケールファイルを展開する必要があります。

  1. en:
  2. スカラクシー:
  3. callback_presence:
  4. 説明:「指定されたコールバックチェーン{{chain}}で{{callback}}の存在を確認します。」
  5. 期待:
  6. is_valid:「{{chain}}の{{callback}}の場合に有効」




spec_helperのmatchers.rbファイルにrequireを追加します。



そして今、私たちの期待を簡単かつ簡単に説明することができます。

  1. クラス Thing < ActiveRecord :: Base
  2. ##コールバック
  3. define_callbacks :after_run
  4. after_run :notify_people
  5. 終わり


  1. 物事を記述する
  2. should_callback_presence :after_run 、:notify_people
  3. 終わり




______________________

テキストは、©SoftCoder.ruのHabr Editorで作成されます。



All Articles