我有一个带Rspec测试套件的Rails应用程序,它具有一些功能/控制器测试,取决于ElasticSearch.
当我们测试系统周围的“搜索”功能(以及依赖于ES的其他功能)时,我们使用了一个真正的ES,当我们运行单一的spec文件时,它在开发环境中工作得很好.
当套件在我们的CI服务器上运行时,它变得很奇怪,因为有时ES将不能保持足够的同步,以使测试成功运行.
我搜索了某种方式以“syncronous模式”运行ES,或者等到ES准备好了,但到目前为止还没有找到任何东西.我已经看到使用Ruby睡眠的一些解决方法,但我觉得不能接受.
我如何保证ES同步运行我的测试?
你在测试套件上如何处理ES?
这是我的一个测试:
context "given params page or per_page is set",:elasticsearch do let(:params) { {query: "Resultados",page: 1,per_page: 2} } before(:each) do 3.times do |n| Factory(:company,account: user.account,name: "Resultados Digitais #{n}") end sync_companies_index # this is a helper method available to all specs end it "paginates the results properly" do get :index,params expect(assigns[:companies].length).to eq 2 end end
这是我的RSpec配置块和ES帮助方法:
RSpec.configure do |config| config.around :each do |example| if example.Metadata[:elasticsearch] Lead.tire.index.delete # delete the index for a clean environment Company.tire.index.delete # delete the index for a clean environment example.run else FakeWeb.register_uri :any,%r(#{Tire::Configuration.url}),body: '{}' example.run FakeWeb.clean_registry end end end def sync_companies_index sync_index_of Company end def sync_leads_index sync_index_of Lead end def sync_index_of(klass) mapping = MultiJson.encode(klass.tire.mapping_to_hash,:pretty => Tire::Configuration.pretty) klass.tire.index.create(:mappings => klass.tire.mapping_to_hash,:settings => klass.tire.settings) "#{klass}::#{klass}Index".constantize.rebuild_index klass.index.refresh end
感谢任何帮助!
解决方法
你的测试很困惑 – 它是测试分配,分页和(隐含)参数传递.打破它:
参数
let(:tire) { double('tire',:search => :sentinel) } it 'passes the correct parameters to Companies.tire.search' do expected_params = ... # Some transformation,if any,of params Companies.stub(:tire).with(tire) get :index,params expect(tire).to have_received(:search).with(expected_params) end
分配
我们只关心代码是取一个值并将其分配给别的东西,这个值是无关紧要的.
it 'assigns the search results to companies' do Companies.stub(:tire).with(tire) get :index,params expect(assigns[:companies]).to eq :sentinel end
这是棘手的一点.您不拥有ES API,因此您不应该存储它,但是您也不能使用ES的实时实例,因为您不能相信它在所有测试场景中都是可靠的,它只是一个HTTP API所有(这是你的根本问题).加里·伯恩哈特(Gary Bernhardt)在他出色的screencasts之一中解决了这个问题 – 您只需要虚构HTTP呼叫.使用录像机
VCR.use_cassette :tire_companies_search do get :index,params search_result_length = assigns[:companies].length expect(search_result_length).to eq 2 end
运行一次成功,然后永远更多地使用磁带(这只是一个YAML文件的响应).您的测试不再依赖于您无法控制的API.如果ES或您的分页宝石更新他们的代码,只需在您知道API正常工作时重新录制磁带.没有任何其他的选择,没有使您的测试非常脆弱或者存在你不应该存根的东西.
请注意,虽然我们已经把轮胎弄坏了,但我们并不拥有它 – 在这些情况下可以确定,因为返回值与测试完全无关.