Hi, my name is Leonid, and I work in a team using Ruby on Rails at Align Technology.
At work, we use rails in conjunction with RSpec, and today I will share our experience on how to make your life easier by using your own tags in tests.
By default, a speck in rails has several directories for grouping tests according to what they test: models, a separate controller, a view, several controllers, and routing.
Inside himself, rspek puts down tags (metadata), according to which he supplements tests in some group with auxiliary methods and new asserts. (Metadata is just a hash in which each folder adds a type key to a given test with the name of this directory)
Each test for its launch gets its own generated class, in which, in fact, DSL modules with the necessary helpers and asserts are mixed in.
You can use your own tags if the properties that your test must satisfy do not allow it to be placed in any particular directory.
Here are some useful tags that we use in our work.
Usually, search libraries in rails are integrated with the ActiveRecord / ActiveModel classes, setting up after_save callbacks for calling the DSL method of configuring indexed fields.
At the same time, one of the popular search libraries Sunspot does not have automatic integration with pspek, that is, your tests will always cause indexing of your models. Most often it seriously slows down the tests, because the search is usually used in tests only in the search controller, and, for example, in the synonyms and ranking tests, as the correct configuration of your search engine.
Let's add a tag-rule that includes sending data to the search engine only when necessary.
spec / spec_helper.rb:
# --- :solr tag --- # By default, Sunspot engine is disabled in any tests, with its connection stubbed. # Add :solr tag to enable regular model indexing. # Don't forget to run your search engine by corresponding rake task before running the suite. config.before :suite do $real_solr_session = ::Sunspot.session ::Sunspot.session = ::Sunspot::Rails::StubSessionProxy.new(::Sunspot.session) end config.before :each, solr: true do ::Sunspot.session = $real_solr_session end config.after :each, solr: true do $real_solr_session = ::Sunspot.session ::Sunspot.session = ::Sunspot::Rails::StubSessionProxy.new(::Sunspot.session) end
Now just mark your tests, which really need a search engine tag : solr .
For example, check if synonyms work correctly in synonyms.txt:
spec / models / document.rb
it 'knows that tienda means store, in case someone will use \'STORE\' among spanish documents' do FactoryGirl.create :document, title: 'Lorem ipsum store dolor sit amet', searchable: true, locales: Locale.find_by(name:'es') Document.reindex Document.solr_search { fulltext 'tienda' }.hits.should have(1).document_match Document.solr_search { fulltext 'store' }.hits.should have(1).document_match end
In fact, for applications with a “small” database, nothing prevents you from using the entire database as one of the “test datasets”.
This will allow to do asserts on real data, as well as test complex migrations.
So, for the tag : seeded tests, which start with live database snapshots, we will need a few things. The first is Rake-task, which gets a fresh snapshot of the database (for example, taken once a day), and, if necessary, cleared of important production data.
The second point is this: restoring the database takes time, so let's first run all the "normal" tests, and then group the tests with the "full" database so that they run at the very end:
spec / spec_helper.rb:
config.order_groups {|list| list.reject{|e| e.metadata[:seeded]}.shuffle(random: Random.new(config.seed)) \ + list.select{|e| e.metadata[:seeded]}.shuffle }
(It is better to use the usual test run mechanism in a transaction, which is canceled at the end of the test)
Note that the Rspec tries to run tests in a random order in order to find problems with the state corrupted by the previous test. (After that, debugging is possible using the same order, if you pass the --seeded flag to pspeku with the value that it prints at startup) Therefore, we follow the agreement and reset the random number generator to the config.seed file.
It remains to set the rules for the tag:
spec / spec_helper.rb:
# --- :seeded tag --- # 1. have all :seeded tags grouped and executed at the end of the test suite # 2. have your SQL test DB filled with fresh data from content master # 3. then migrated from your migrations # REQUIREMENTS: # A. all :seeded tests run one after another # B. :seeded tag is put on the top 'describe' blocks config.before :all, seeded: true do unless $rspec_seeded_database Rails.application.load_tasks Rake::Task['db:restore_from_snapshot '].invoke Rake::Task['db:migrate'].invoke $rspec_seeded_database = true Rails.application.reload_routes! #Rake::Task['sunspot:reindex'].invoke end end config.after :all, seeded: true do end
Well, in db: restore_from_snapshot, cache the downloaded snapshot of the database in the tmp / folder in order to not download it to the developer’s machine each time.
Even better: we can use the same requests tests to test the live application. Of course, this is possible only if they do not work with the database at all, or read the same data from the database as in the deployed server.
Write your tag:
spec / spec_helper.rb:
config.before :each, also_for_smoke_test: :true do Capybara.run_server = false Capybara.app_host = ENV['ACCEPTANCE_URL'] Capybara.current_driver = :webkit end
Now we run only the necessary part of our tests as a smoke test script:
ACCEPTANCE_URL=https://your-host.com rspec -t also_for_smoke_test
And what rules tags do you use?
Source: https://habr.com/ru/post/303998/
All Articles