open ai apiのテストコード

let(:mock_openai_client) { double('OpenAI::Client') }
before do
allow(OpenAI::Client).to receive(:new).and_return(mock_openai_client)
end
OpenAI::Client.new が呼び出されたときに、実際のオブジェクトの代わりにこのモックオブジェクトを返すように指定。
{double('OpenAI::Client') } とすることで、OpenAI::Client のモックオブジェクトが作成される。
このモックオブジェクトは、実際の OpenAI::Client オブジェクトと同じインターフェース(つまり同じメソッドやプロパティ)を持ちますが、実際のAPIとの通信は行わない。

before do ブロック内で allow を使用する理由は、テストの実行前に特定の設定やモックを事前に準備しておくことが重要だからです。この場合、OpenAI::Client.new と mock_openai_client の chat メソッドが呼ばれるときの振る舞いを事前に定義しています。
テスト中にユーザーがフォームに入力して変換ボタンをクリックすると、コントローラーが OpenAI::Client.new を呼び出します。before do ブロックで allow(OpenAI::Client).to receive(:new).and_return(mock_openai_client) と設定することで、実際にこのメソッドが呼び出されたときにモックオブジェクトが返されるようになります。つまり、コントローラーがこのメソッドを呼び出すタイミングで、すでにモックが用意されており、実際のAPI呼び出しを行わないようになっています。
このように事前にモックを設定しておくことで、テストの実行時にコードが予定通りの振る舞いをすることを保証し、外部依存性(この場合はOpenAIのAPI)を排除することができます。これにより、テストはより高速で信頼性が高く、独立して実行できるようになります。

describe '自己受容トレーニング結果' do
let(:user) { create(:user) }
let(:mock_openai_client) { double('OpenAI::Client') }
let(:mock_response) {
{
'choices' => [
{ 'message' => { 'content' => '変換されたポジティブなメッセージ' }}
]
}
}
before do
login(user)
visit new_self_esteem_training_path
allow(OpenAI::Client).to receive(:new).and_return(mock_openai_client)
allow(mock_openai_client).to receive(:chat).and_return(mock_response)
end
it '自己否定的なテキストを自己受容のメッセージに変換する' do
fill_in 'text', with: '自己否定的な思考'
click_button '変換'
sleep 15
expect(page).to have_text('変換されたポジティブなメッセージ')
expect(page).to have_current_path(result_self_esteem_trainings_path, ignore_query: true)
end
end
allow(mock_openai_client)の説明
-
モックの設定:
- テストの前処理(
before do
ブロック内)で、OpenAI::Client
クラスが新しいインスタンスを生成するたびにmock_openai_client
を返すように設定されています(allow(OpenAI::Client).to receive(:new).and_return(mock_openai_client)
)。
- テストの前処理(
-
コントローラーでの処理:
- コントローラー内で
@client = OpenAI::Client.new(access_token: @api_key)
が呼び出されると、テスト設定に基づき、実際にはmock_openai_client
が@client
として設定されます。
- コントローラー内で
-
モックの反応:
- その後、コントローラーで
@client.chat
が呼び出されると、これは実際にはmock_openai_client.chat
の呼び出しとなります。これは、@client
がmock_openai_client
の参照を持っているためです。
- その後、コントローラーで

例えば以下のようなパスが返されるとき、クエリパラメータ (text=自己否定的な思考) の部分を省いてURLのパス部分のチェックしたいい場合。
ページのURLパス:(/self_esteem_trainings/result?text=自己否定的な思考)
ignore_query: trueを付けることでクエリパラメータは無視され、URLのパス部分のみがチェックされる。
expect(page).to have_current_path(result_self_esteem_trainings_path, ignore_query: true)