LoginSignup
38
35

More than 5 years have passed since last update.

elasticmqを使ったsqsとの連携テスト

Last updated at Posted at 2015-05-25

背景

Amazon SQS。自分のサービスにメッセージキューサービスをとても簡単に組み込めて便利。
http://aws.amazon.com/jp/sqs/

しかし、いざそれを使った機能のspecを書こうと思うと、「外部サービスだからstub書かなきゃ」という辛みと、「結合テスト的に実際にAPI叩きたいし」という欲求が出てきて、どうしたらいいのよ :scream: 、という感じになる。

そりゅーしょん

環境用意すれば良いじゃない!

ElasticMQ
https://github.com/adamw/elasticmq

こちら、Amazon SQS-compatible interfacesという素晴らしい特徴を持ったメッセージキューシステムです。

これをローカルに立ち上げれば、そもそも普通の開発の時からローカルでキューシステム使った検証できるし、何よりrspecからキューへの登録、取得などのテストもちゃんとAPIを叩いた上で通すことができる。

注意

以下は、rails環境でrspecを利用することを想定しています。

準備

まずは、ElasticMQを用意。ローカルに普通にダウンロードしても良いけど、CircleCIとかでの利用を見越すとDockerコンテナとして用意しておくのが良さげ。

FROM java:8

# Create working space
RUN mkdir /var/elasticMQ
WORKDIR /var/elasticMQ

# Default port for SQS Local
EXPOSE 9324

# Get the package from Amazon
RUN wget -q https://s3-eu-west-1.amazonaws.com/softwaremill-public/elasticmq-server-0.8.8.jar

# Default command for image
ENTRYPOINT ["/usr/bin/java", "-Djava.library.path=.", "-jar", "elasticmq-server-0.8.8.jar"]

spec_helper

spec_helperのほうに、以下の設定を書く。
IPはboot2dockerでelasticmqを立ち上げたときの値なので、必要に応じて127.0.0.1とかにすると良い。
ここではサンプルなので、キューの名前も決め打ちで一つだけにしているけど、実際には設定ファイルから読みこんだ値を使うなどよしなに。

# rspec内では常に以下のクライアントを使う 
sqs_client = Aws::SQS::Client.new(
  region:             'dummy-sqs',
  endpoint:           "http://192.168.59.103:9324",
  access_key_id:      'dummy',
  secret_access_key:  'dummy',
)

regionやアクセスキーなどの値は適当な値でも大丈夫そう(今のところ)。aws-sdkのversionが上がったりするとその辺のvalidationが走ってダメになるかも。今回試したのは2.0.42。

# 事前にqueueを作っておく
# 必要に応じて特定のspecでのみキューを作成するなどにしても良い
config.before(:suite) do
  # 都度都度Clientをstubするのが面倒なので`new`自体をstubする
  allow(::Aws::SQS::Client).to receive(:new).and_return(sqs_client)
  sqs_client.create_queue(queue_name: "sample_jobs")
  # http://192.168.59.103:9324/queue/sample_jobs
  # が作成したqueue_urlとなる
end
# テストが終わったらqueueのメッセージを消す
# purge処理は即時実行される訳ではないので、次のspec実行時にメッセージが残っている可能性あり
config.after(:each) do
  sqs_client.purge_queue(queue_url: "http://192.168.59.103:9324/queue/sample_jobs")
end

spec

以上の準備ができたら、以下のようなモデルとspecを書いてみる。

class JobRegister
  class << self
    def client
      Aws::SQS::Client.new(
        region: 'ap-northeast-1' # 実際には決め打ちにすんなよ!
      )
    end

    def register message
      client.send_message(
          queue_url: "http://192.168.59.103:9324/queue/sample_jobs", # この辺も実際にはよしなにね!
          message_body: {
            message: message,
          }.to_json
        )
      end
    end 
  end
end
spec/models/job_register_spec.rb
require 'spec_helper'
describe JobRegister do
  describe '.register' do
    it 'ジョブが登録されていること'
      described_class.register "hello"
      message = described_class.client.receive_message(queue_url: "http://192.168.59.103:9324/queue/sample_jobs").messages.first
      expect(JSON.parse(message.body)["message"]).to eq "hello"
    end
  end
end

というspecが通るようになる。

注意

queue_urlにlocalhostを使うには、
http://dev.classmethod.jp/server-side/ruby-on-rails/ruby_aws-sdk-core_elasticmq_sqs/
に記載のある通り、パッチを当てる必要がある。しかし、aws-sdkの実装を見る限り"."でsplitした結果からregionを取得してるようなので、"127.0.0.1"のように"."さえ入っていればパッチは当てなくても動いた。

まとめ

とりあえずrspecからelasticmqを叩けた。CircleCIにコンテナを持って行けば、CI環境で結合テストも可能。

38
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
35