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で作成されます。

Source: https://habr.com/ru/post/J73862/


All Articles