Techioz Blog

すでにお気づきのとおり、SQL の実行には厳密な順序があり、意図したとおりに動作します。 順序は、where によってすでにフィルターされた結果セットにのみ適用されます。 データを取得してフィルタリングする方法について、アプローチを再考することをお勧めします。

概要

三目並べボードの表示をテストする仕様を作成しようとしています。メソッドキャプチャを使用していますが、仕様を実行するとエラーがスローされます。メソッド呼び出しの出力を取得するためにキャプチャを使用しています。 https://apidock.com/rails/Kernel/capture 私の方法は次のとおりです。

  def display_board
    puts " #{grid[0]} | #{grid[1]} | #{grid[2]} "
    puts "-----------"
    puts " #{grid[3]} | #{grid[4]} | #{grid[5]} "
    puts "-----------"
    puts " #{grid[6]} | #{grid[7]} | #{grid[8]} "
  end

私のRspecテストは次のとおりです。

context "#display_board" do
     output = capture(:stdout) { board.display_board}
     rows = output.split("\n")
     binding.pry
     expect(rows[0]).to eq("   |   |   ")
     expect(rows[1]).to eq("-----------")
     expect(rows[2]).to eq("   |   |   ")
     expect(rows[3]).to eq("-----------")
     expect(rows[4]).to eq("   |   |   ")
  end

解決策

問題は、#capture が非推奨となり削除されたことです。

個人的には、I/O をゲーム コンテンツの生成から分離するほうが作業とテストが容易になるためです。したがって、puts の代わりに、ボードを含む文字列を構築するだけです ( 各行の末尾に) を入力して、それが正しいかどうかをテストします。実際のゲームでは、1 回の put 呼び出しでボードをコンソールに出力します。

本当に STDOUT をキャプチャしたい場合は、方法があります。現在の STDOUT ストリームへの参照を含むグローバルです。デフォルトでは、これは常に STDOUT (プログラムの実際の STDOUT を表す定数) に設定されますが、別の IO ストリーム (たとえば StringIO オブジェクト) にリダイレクトできます。 put は、STDOUT に直接書き込む代わりに、参照するものに書き込みます (そこには微妙な違いがあります!)。

$stdout = StringIO.new
puts 'this is my output'
captured_output = $stdout.string
$stdout = STDOUT # restore it when you're done

これで、「これは私の出力です」(その後に改行文字が続きます)がcaptured_outputにキャプチャされました。ただし、その間に STDOUT に出力された他のものもあるため、理想的ではありません (Ruby コンソールのコンソール出力など)。常に復元されることを保証するメソッドでそれをラップする必要があります。

def capture() 
  $stdout = StringIO.new
  yield
  $stdout.string
ensure
  $stdout = STDOUT
end

これをブロックと一緒に使用できます。

capture { puts 'xyz' } 
=> 'xyz\n'

(ただし、このアプローチを忘れて、ボードを文字列として構築した方が楽になります。)