我尝试写了包含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的表中的数据。

idname1xxxx2xxxx

定义将数据放入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 可以尝试以下的自然语言转换技术,只需一个选项:

广告
将在 10 秒后关闭
bannerAds