Symbol ストリーム名をリテラルとして扱うテストアサーションの統一
ActionCable のテストアサーションで Symbol が文字列と同等に扱われず、偽陰性や偽陽性が発生していた問題を解消します。変更は ActionCable::Channel::TestCase に型変換ロジックを追加し、API とテストの整合性を高めます。
背景
stream_from(:my_room) が実行時に String に変換 され、リテラルストリーム名 "my_room" として扱われることは既に実装で保証されています。にもかかわらず、テストアサーションの assert_broadcasts 系 と assert_has_stream 系 が Symbol を文字列に統一せず、期待するストリームと不一致になるケースがありました。たとえば assert_broadcasts(:my_room, 1) は実際にブロードキャストが送信されても 0 と報告し、assert_has_no_stream(:my_room) はストリームが存在しても成功してしまうという false‑green が発生していました。これらは ActionCable の実運用 API とテストコードだけが食い違う例であり、テスト結果の信頼性を低下させる要因でした。
技術的な変更
broadcasting_for の拡張
ActionCable::Channel::TestCase#broadcasting_for が Symbol をそのまま返すようロジックを追加し、String と同様にリテラルストリーム名へ変換できるようにしました。
@@
- return stream_or_object if stream_or_object.is_a?(String)
+ return stream_or_object if stream_or_object.is_a?(String) || stream_or_object.is_a?(Symbol)
この変更により、assert_broadcasts と assert_broadcast_on が内部で呼び出す broadcasting_for が Symbol を正しく処理し、期待通りのストリームを参照できるようになります。
assert_has_stream / assert_has_no_stream の文字列化統一
assert_has_stream と assert_has_no_stream でも引数を明示的に String(stream) に変換し、比較対象をストリーム名の文字列表現に統一しました。
def assert_has_stream(stream)
check_subscribed!
stream = String(stream)
assert subscription.stream_names.include?(stream), "Stream #{stream} has not been started"
end
def assert_has_no_stream(stream)
check_subscribed!
stream = String(stream)
assert subscription.stream_names.exclude?(stream), "Stream #{stream} has been started"
end
テストケースの追加
新しいシンボルストリームに対するテストが追加され、修正の効果が検証されています。
class SymbolStreamsTestChannel < ActionCable::Channel::Base
def subscribed
stream_from :my_room
end
end
class SymbolStreamsTestChannelTest < ActionCable::Channel::TestCase
def test_assert_has_stream_with_symbol_broadcasting
subscribe
assert_equal ["my_room"], subscription.stream_names
assert_has_stream :my_room
end
def test_assert_has_no_stream_with_symbol_broadcasting
subscribe
assert_raises(Minitest::Assertion) { assert_has_no_stream :my_room }
end
end
設計判断
後方互換性の確保を最優先し、メソッドシグネチャや公開 API は変更していません。シンボルを文字列へ明示的に変換するだけなので、既存コードが assert_broadcasts(:my_room) を使用していても動作に差異は生じません。さらに、一貫した型変換戦略をテストアダプタ層(#57698)とテストケース層の両方に適用したことで、スタック全体で同一ロジックが共有され、今後のメンテナンスコストが低減します。最小限の侵入で実装されたため、他の ActionCable 機能への副作用リスクも低く抑えられました。
まとめ
この PR は Symbol と String のストリーム名取り扱いを統一し、テストアサーションが本番 API と食い違う問題を根本から解消します。型変換のみのシンプルな変更で false‑negative/false‑positive を防止し、ActionCable のテスト信頼性と保守性を向上させました。