Techioz Blog

Ruby と Cucumber を使用して非同期動作をテストするにはどうすればよいですか?

概要

Ruby、Cucumber、Capybara、SitePrism を使用した新しい自動テスト プロジェクトを開始しています。これは、クリーンで保守が容易なアーキテクチャを定義する機会です。 ただし、非同期動作のテストという、洗練された解決策が見つからないという課題がすでにあります。

テストする必要がある非同期動作の 1 つは電子メールの送信です。販売が完了すると、システムは購入者に電子メールを送信します。電子メールが正しく送信されたかどうかをテストする必要があります。ただし、電子メールの送信はすぐには行われません。 、キューに入れられ、実行に時間がかかります (1 ~ 3 分程度)。

システムは、テスト環境でツールを使用して、送信された電子メールをデータベースに保存します。私はそのデータベースにアクセスして、電子メールの件名を検索し、受信者をアサートしています。

シナリオ定義は次のようになります。

Scenario: Send sale email
Given I'm logged in as "send_sale_email"
When I make a sale
Then the system should send a sale confirmation email

そして、step_settings では次のようになります。

Then "the system should send a sale confirmation email" do
  buyer_email = '[email protected]'
  email_subject = "Sale confirmation #{@sale_number}"
  email_recipients = get_email_recipients(email_subject)
  expect email_recipients.to include(buyer_email)
end

しかし、販売が完了し、テストがデータベースにアクセスするとき、電子メールはまだ送信されておらず、いつ送信されるかについての保証はありません。時々再試行する方法を作成しました。うまくいきました。

Then "the system should send a sale confirmation email" do
  buyer_email = '[email protected]'
  email_subject = "Sale confirmation #{@sale_number}"
  sleep_time = 30
  max_retries = 6
  retry_count = 0
  begin
    email_recipients = get_sent_email_recipients(email_subject)
    expect(email_recipients).to include(buyer_email)
  rescue RSpec::Expectations::ExpectationNotMetError => e
    if retry_count <= max_retries
      retry_count += 1
      sleep sleep_time
      retry
    end
    raise e
  end
end

この方法では約 3 分間待機しますが、テストにスリープを入れるのは良くないようです。また、システムにはそのような複数の操作があり、ページをリロードして何かを検索する必要がある場合もあります。再試行ロジックを分離して再利用できることはわかっていますが、時間の経過とともにメンテナンスの悪夢になるでしょうか?非同期動作をテストするためのより洗練された方法はありますか?

解決策

私なら次のようにします:

非同期タスクが作成されたときに実際に実行されるかどうかのテストは、個別に行う必要があります。これらのテストでは、睡眠を使用する必要がある場合があります

クリーンで高速な機能テストが可能になります