RSpec スーパークラスの不一致 (Sinatra)
概要
Sinatra API 用の仕様ファイルがいくつかあります。彼らはモジュール MysuperBlog とそのモジュール内のクラス API をテストします。
RSpec 構成ファイルにこれがあります:
RSpec.shared_context 'Reset class' do
after(:each) do
Object.send(:remove_const, :API)
end
end
仕様ファイルにはすべて次のコード行が含まれています。
require 'rack/test'
require 'json'
require_relative '../../../app/main.rb'
module MysuperBlog
class API
RSpec.describe 'An author logs in to his account', type: :request do
include_context 'Reset class'
メインのアプリ ファイルには次のものが含まれます。
module MysuperBlog
class API < Sinatra::Base
各 spec は成功しますが、引数なしで rspec を実行すると、エラーが発生します。
TypeError:
superclass mismatch for class API
これは、各ファイルでモジュールとクラスが定義されていることが原因だと思います。
個々のテストとグローバル テストの両方がこのエラーなしで合格するには、コードをどのように並べ替えればよいでしょうか?
解決策
Ruby の class キーワードには、クラスを作成することと、既存のクラスを再度開くことの 2 つの目的があります。
クラスに Object 以外のスーパークラスがある場合、クラスを作成するときにそれを指定する必要がありますが、クラスを再度開くときには省略できます。例: (デモの目的でのみ Array を使用しています。コア クラスをサブクラス化すべきではありません)一般的に)
class Foo < Array ; end
class Foo ; end # <- works
逆に行うと、表示されているエラーが発生します。
class Foo ; end
class Foo < Array ; end # <- TypeError: superclass mismatch for class Foo
クラスを作成し、そのスーパークラスを指定するファイルの前に、既存のクラスを再度開くことになるファイルをロードすると仮定します。
その場合は、必ず後者を最初にロードしてください (仕様ヘルパーなどで必須にしてください)。そうすれば問題は解決するはずです。
実際に既存のクラスを再度開くのではなく、テスト内の別の使い捨てクラスに同じクラス名を再利用しようとする場合は、クラスの使用が完了した後に、remove_const を使用して定数を削除できます。 / test:(例:フック後の RSpec 内)
class Foo < Array ; end
Object.send(:remove_const, :Foo)
class Foo < String ; end # different Foo, no error
このようにして、各クラス Foo は、前のクラスを再度開くのではなく、新しい独立したクラスを作成します。
オブジェクトはトップレベルの定数に使用されます。ネストされた定数の場合は、Object を実際に定数を保持するモジュールに置き換えます。