我尝试写了包含Elasticsearch的Rspec请求规范
环境
Rails和Elasticsearch分别在不同的容器中运行。
services:
elasticsearch:
image: elastcserachのdockerイメージ
(以下省略)
rails:
image: railsのdockerイメージ
(以下省略)
为了测试目的,添加了一个Gem。
可以在不同端口(默认为9250)上启动用于测试的集群。
链接:https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-extensions
启动用于测试的集群
使用elasticsearch时只需启动,结束后即可停止。
require 'elasticsearch/extensions/test/cluster'
before(:context) do
Elasticsearch::Extensions::Test::Cluster.start(nodes: 1) unless Elasticsearch::Extensions::Test::Cluster.running?
end
after(:context) do
Elasticsearch::Extensions::Test::Cluster.stop if Elasticsearch::Extensions::Test::Cluster.running?
end
运行时会出错。
(Note: The translation assumes Simplified Chinese script)
Cannot find Elasticsearch launch script from [elasticsearch] -- did you pass a correct path?
由于Elasticsearch和Rails的容器不同,必须在Rails容器中启动Elasticsearch,需要先确保Rails容器可以使用Elasticsearch。
为了改变方向,就像对数据库进行操作一样,需要准备一个用于测试的索引(同时删除之前添加的gem)。因此,需要根据不同环境来区分alias_name。
def alias_name
"players_#{Rails.env}"
end
这次处理的数据
处理一个包含选手id和姓名列的名为Player的表中的数据。
定义将数据放入Elasticsearch中如下:
require 'elasticsearch/model'
module SearchablePlayer
extend ActiveSupport::Concern
included do
include Elasticsearch::Model
include Indexing
index_name "players_#{Rails.env}_#{Time.now.strftime('%Y%m%d%H%M%S')}"
settings do
mappings dynamic: false do
indexes :id, type: 'integer'
indexes :name, type: 'string'
end
end
end
module Indexing
def as_indexed_json(options={})
{
id: id,
name: name,
}
end
end
module ClassMethods
def alias_name
"players_#{Rails.env}"
end
end
end
将数据放入用于测试的群集。
在rspec内定义一个方法,将表中的数据反映到elasticsearch中。
由于数据到elasticsearch的反映需要时间,所以在方法中加入1秒的sleep。
此时,索引名称将是”players_test”,对开发环境的索引不会产生影响。
def elasticsearch_update
index_name = Player.index_name
alias_name = Player.alias_name
# Playerのindexを追加
Player.__elasticsearch__.import(
force: true,
index: index_name
)
# Playerのindexを追加
actions = [{
add: {
index: index_name,
alias: alias_name
}
}]
Player.__elasticsearch__.client.indices.update_aliases(
body: { actions: actions }
)
# インデックスに反映するために1秒待つ
sleep 1
end
写请求规范
这次测试是编写一个返回运动员列表的API。可以在之前先创建一张表并插入记录,然后调用之前定义的方法。
describe '選手の一覧を返却するAPI'
before do
# データを作成する
FactoryBot.create(players, name: 'test')
# 作成したデータをelasticsearchへ反映させる
elasticsearch_update
end
it do
get 選手一覧のAPIパス
expect(レスポンスの選手名).to eq(test)
end
end
完成考试后删除索引。
由于当前的状态,每次执行测试时都会增加索引,因此在测试完成后需要删除索引。
另外,由于还有一种情况是不向elasticsearch投入数据,所以可能会出现NotFound异常,需要进行异常处理(可能还有更好的方法)。
after(:example) do
player_client = Player.__elasticsearch__.client
alias_name = Player.alias_name
begin
delete_indices = player_client.indices.get_alias(name: alias_name).keys
player_client.indices.delete(index: delete_indices)
rescue Elasticsearch::Transport::Transport::Errors::NotFound
end
end
总结
尽管无法使用gem(Elasticsearch::Extensions),但可以通过创建测试索引来写足够的测试,就像数据库操作一样。(似乎也没有特别的负面影响?)
引用
https://techlife.cookpad.com/entry/2015/09/25/170000 可以尝试以下的自然语言转换技术,只需一个选项: