16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RSpecでDynamoDBのユニットテストを実装

Last updated at Posted at 2015-02-26

注意事項

現在、FakeDynamo はメンテナンスが終了しており、利用は非推奨です。
DynamoDB のユニットテストを実装される方は、DynamoDB Local をご使用ください。

This project is no longer maintained. Checkout Amazon
DynamoDB Local if you are looking for
implementation of latest version.

ananthakumaran/fake_dynamo

RSpec を使って DynamoDB Local を用いる方法については、

などが参考になるかと思います。

余談

TravisCI で DynamoDB Local を用いた RSpec によるユニットテストの導入に関わることがあったので、機会があればそちらもまとめてみようと思います。
また、Circle CI への DynamoDB Local の導入も予定しているので、実現したらそちらもまとめようかと思います。

き、気が向いたら!笑

概要

FakeDynamo というローカルで実行できる DynamoDB のエミュレータを利用し、DynamoDB を使用しているプログラムのユニットテストを RSPec で実装してみました。

Amazon DynamoDB

Amazon DynamoDB は、1 桁台のミリ秒単位のレイテンシーを必要とするすべての規模のアプリケーションに対応した高速かつフレキシブルな NoSQL データベースサービスです。

いわゆる NoSQL で、データモデルは Tables, Items, Attributes だそうです。
こちらのスライドにザッと目を通すと良いかと思います。

FakeDynamo

local hosted, inmemory Amazon DynamoDB emulator.

ローカルで動作する Amazon DynamoDB のインメモリなエミュレータです。こいつを DynamoDB の代わりに利用します。

導入

README の Usage 通りに Gem を導入し、起動後に初期化すれば終了です。

なーんとなくポートが使われていないか調べてから起動しました。

$ netstat -na | grep 4567
$ fake_dynamo --port 4567

そして初期化。

$ curl -X DELETE http://localhost:4567

動作確認

DynamoDB へのアクセスに使うモデルはAWS::Record::HashModelを使って実装しました。
このクラスの使用方法については、[Ruby on Rails] AWS::Record::HashModel を使って Amazon DynamoDB のモデルを作るを参考にしてます。

class User < AWS::Record::HashModel
  def self.inherited(subclass)
  end
  
  set_shard_name "users"
  string_attr :user_id
  string_attr :email
end

そして fake_dynamo を起動します。

$ fake_dynamo --port 4567

動作確認ということで、rails console で実行してみました。

$ rails console

# 公式サイトに従い設定
pry(main)> AWS.config(:use_ssl => false,
                      :dynamo_db_endpoint => 'localhost',
                      :dynamo_db_port => 4567,
                      :access_key_id => "xxx",
                      :secret_access_key => "xxx")
=> <AWS::Core::Configuration>

# テーブルの作成
pry(main)> User.create_table 1, 1, :shard_name => 'users'
AWS::DynamoDB::Errors::ValidationException: Validation error detected: KeySchema must be a Array
from /usr/local/lib/ruby/gems/1.9.1/gems/aws-sdk-1.48.1/lib/aws/core/client.rb:375:in `return_or_raise'

ダメでした。

エラーメッセージで調べてみると Dynamoid という DynamoDB の ORM の Issue にそれらしいコメントがありました。どうやら、古いバージョンを入れたら解決するとのこと。

原因はどうやら、使っている AWS-SDK が古いこと(1系)のようです。
DynamoDB の API Version 2012-08-10 では、2系の AWS-SDK にしか対応してないためした。

You should use an older version of fake_dynamo. You should be able to see the version you are using by typing gem list | grep fake_dynamo in terminal.

To install the right version try gem install fake_dynamo --version 0.1.3.

Running tests against 2012-08-10 API fails #108

仕方がないので古いバージョンを入れて再度動作確認!

# 公式サイトに従い設定
pry(main)> AWS.config(:use_ssl => false,
                      :dynamo_db_endpoint => 'localhost',
                      :dynamo_db_port => 4567,
                      :access_key_id => "xxx",
                      :secret_access_key => "xxx")
=> <AWS::Core::Configuration>

# テーブルの作成
pry(main)> User.create_table 1, 1, :shard_name => 'users'
=> <AWS::DynamoDB::Table table_name:pixta_credentials>

# インスタンスの生成
pry(main)> user = User.new(user_id: 1, email: "foobar@sample.com")
=> #<User:0x000000086e6e70
 @_data={"user_id"=>1, "email"=>"foobar@sample.com"},
 @_ignore_changes=false,
 @_orig_values={"user_id"=>nil, "email"=>nil},
 @_shard="users">
 
# データベースへ保存
pry(main)> user.save
=> true

動きました!

RSpec で FakeDynamo を使う

Google 大先生に聞いたところ、Starting up fake_dynamo automatically with rspec test suiteというステキなサイトを教えていただきました。

こちらを参考にspec/support内に以下のdynamo.rbを追加しました。

spec/support/dynamo.rb
# FakeDynamoを使うための初期設定
AWS.config(:use_ssl => false,
           :dynamo_db_endpoint => 'localhost',
           :dynamo_db_port => 4567,
           :access_key_id => "xxx",
           :secret_access_key => "xxx")

# FakeDynamoをRSpec実行時に実行
RSpec.configure do |config|
  dynamo_thread = nil

  config.before(:suite) do
    FakeDynamo::Storage.db_path = "#{Rails.root}/tmp/db.fdb"
    #FakeDynamo::Logger.setup(:warn) # version 0.1.3 には存在しない
    FakeDynamo::Storage.instance.load_aof

    dynamo_thread = Thread.new do
      $stdout = open("/dev/null", "w") # FakeDynamo の標準出力を無効化
      FakeDynamo::Server.run!(port: 4567, bind: 'localhost') do |server|
        if server.respond_to?('config') && server.config.respond_to?('[]=')
          server.config[:AccessLog] = []
        end
      end
    end
  end

# FakeDynamoをRSpec終了時に終了
  config.after(:suite) do
    FakeDynamo::Storage.instance.shutdown
    dynamo_thread.exit
  end

これで、実行時に FakeDynamo が立ち上がるようになります。本当は良くないですが、詳細については理解せずに流用してます。

Spec ファイルではbefore(:all)を使い、データベースの初期化とテーブルのクリエイトを最初に行うようにしました。

spec/model/user_spec.rb
require 'spec_helper'

describe User do
  before(:all) do
    # DBの初期化
    Net::HTTP.start('localhost', 4567).delete('/')
    
    # テーブルの作成
    create_opts = {}
    create_opts[:hash_key] = { User.hash_key => :string }
    AWS::DynamoDB.new.tables.create(User.shard_name, 1, 1, create_opts)
  end

  before do
    @user = User.new(user_id: 1, email "foobar@hoge.com")
  end

  subject { @user }

  it { should respond_to(:user_id) }
  it { should respond_to(:email) }

  it { should be_valid }
end

これで DynamoDB を用いたプログラムのユニットテストを RSpec で実装できました。

16
16
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
16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?