简体   繁体   中英

Rails: Integration testing thinking_sphinx with cucumber and webrat - how do I index transactional fixtures?

I'd like to have some Cucumber/webrat integration tests of my search features that use thinking_sphinx & sphinx but the problem is that the data is loaded and then rolled back in a transaction during a typical cucumber test so there is no way for thinking_sphinx to index it. Alternatively, is there a way to turn transactions off for just a subset of tests?

Have you solved this problem?

[edit - please don't suggesting mocking out the search results. I want the integration test to test the integration of all the features including thinking_sphinx].

We were able to get our cucumber tests to work successfully with thinking sphinx by using a database cleaner plugin and modifying our features/support/env.rb as follows:

# Sets up the Rails environment for Cucumber
ENV["RAILS_ENV"] ||= "cucumber"

...

# http://github.com/bmabey/database_cleaner
require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
Before do
  DatabaseCleaner.clean
end

ThinkingSphinx::Configuration.instance.build
ThinkingSphinx::Configuration.instance.controller.start
at_exit do
  ThinkingSphinx::Configuration.instance.controller.stop
end
ThinkingSphinx.deltas_enabled = true
ThinkingSphinx.updates_enabled = true
ThinkingSphinx.suppress_delta_output = true

# Re-generate the index before each Scenario
Before do
  ThinkingSphinx::Configuration.instance.controller.index
end

As you can see, we also created a 'cucumber' environment and a separate database (in order to run cucumber and specs simultaneously without conflicts) - so you will need to add a 'cucumber:' entry to your database.yml and sphinx.yml if you would like to do that as well.

I see the problem being in this statement:

the data is loaded and then rolled back in a transaction during a typical cucumber test so there is no way for thinking_sphinx to index it

It may not be fast to have thinking_sphinx index the results, but it's certainly possible within the transaction. Since it's a single integration test, and not done for each of your (many) unit tests, I'd take the speed hit.

So now you need to figure out how to trigger that re-index during a transaction.

# somewhere in /features/support:
before('@reindexing') do
  require 'Rake'

  class MyModel
    after_save :force_reindex!

    def force_reindex!
      # in case multiple runs of this block cause the hook
      # to get added multiple times, let's check to make sure
      # we haven't already reindexed for this save
      return if @__reindexed
      Rake["thinking_sphinx:rebuild"].execute
      @__reindexed = true
    end
  end
end

after('@reindexing') do
  class MyModel
    def force_reindex!
      # do nothing; the hook still gets called, but that's ok
    end
  end
end

In /features/integration.feature (or whatever), you'd have

@reindexing
Feature: The whole shebang, altogether

  Scenario: ...

The linked suggestion won't work, because the Rake task invokes the indexer in a seperate process, and so is outside of the test transaction.

I don't know that there's any way around this, other than turning off test transactions so that the sphinx index process can see new and updated records. To do that, in your TestCase , just add the line

self.use_transactional_fixtures = false

Bear in mind that you'll need to manage clearing up any data at the end of your test.

另一个使用标签来分隔黄瓜思维狮身人面像测试的示例, 此处使用了黄瓜标签。

I would not recommend you test a component that you don't own. It will be a pretty brittle test since it would be dependent on the specific ranking algorithm in that specific version of sphinx that could change later and thus return unpredictable results in the future.

if you want to do this I would however suggest running a separate index for testing either using the test database via the mysql adapter or the xmlpipe2 option (xml2pipe obviously lets you change your data set without having to change the indexing options in your sphinx file). This will probably require that you set up your test data separately all at once, delete the indexes (using ruby shell commands) and then force the reindexing (waiting for the total number of indexed documents to be the same as the known amount of database records) and run your tests against the data.

I would really caution against testing the index like I said you might just find yourself having to deal with a constantly breaking test or slow test runtime (depending on the amount of data you are indexing)

这可能比它的价值更麻烦,但是您是否尝试过打开增量索引?

I tried the suggested solution but sphinx times out with the following error. I don't think it is possible to re-index sphinx while transactional fixtures are enabled.

ERROR: index 'document_core': sql_query_pre[0]: Lock wait timeout exceeded; try restarting transaction

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM