Collection of sample RSpec test templates focused around a Sufia 7 application.
Download this repo to your workstation and use it as a starting-point for experimenting with different testing techniques using Hydra.
git clone https://github.com/awead/hydra-rspec-templates
bundle install
bundle exec fcrepo_wrapper --config config/fcrepo_wrapper_test.yml &
bundle exec fcrepo_wrapper &
bundle exec solr_wrapper --config config/solr_wrapper_test.yml &
bundle exec solr_wrapper &
bundle exec rspec
This will install the gems, start up Fedora and Solr instances in the background, and runs the tests. You will see pending messages and failures. Look at the README for the topics covered here which includes linked files of code for you to use as a starting point for setting up your own applications.
These gems download, configure, and manage running instances of Fedora and Solr. You'll need one each for test and development environments.
When running your feature tests, the entire page will be rendered as if it's in a browser. Capybara will do this and will also test javascript if you provide a driver.
- capybara-screenshot lets you use save_and_open_page at any point during a test to see the web page
- poltergeist is a JS driver for capybara
- factory_girl_rails - a fixtures replacement with a straightforward definition syntax, support for multiple build strategies...
- database_cleaner - Strategies for cleaning databases in Ruby. Can be used to ensure a clean state for testing.
- devise - Flexible authentication solution for Rails with Warden.
- byebug (Ruby 2.0 only) -
- pry - An IRB alternative and runtime developer console
- better_errors with binding_of_caller - Retrieve the binding of a method's caller in MRI 1.9.2+
- webmock - Library for stubbing and setting expectations on HTTP requests in Ruby.
- testing one or more Rubies
- sending out messages
- using a matrix to speed up the test suite
- installing dependencies
- configuration and startup of solr_wrapper and fcrepo_wrapper
More information at docs.travis-ci.com
For further reference, Betterspecs.org provides a series of "best practices" for RSpec.
-
tests should tell a story
-
use
describe
,context
,it
andspecify
-
start with empty tests that tell a story
-
test output should read (more or less) like plain English
"the thing when first created has no name"
"the thing when first created its default values includes the person who's creating it"
"the thing when first created its default values contains that"
"the thing when first created its default values contains this"
- test each Ruby class in isolation using mocked collaborating objects as much as possible
- run integration tests--usually features--that test the class in context with the others
- the Hydra stack is slow, you have to work at it to make it fast
- using careful mocking and stubbing of the application's objects and responses
- write long feature tests and use them judiciously
- prefer
.new
to.create
, or.build
to.create
with FactoryGirl
In a perfect world, each spec has one expectation. The specs are easier to describe if there is one expectation.
However, with a slow stack or an expensive setup, one expectation per spec may be counter-performant. It is okay to have more than one expectation per spec; Just be mindful that it becomes harder to understand what is going on with that spec.
For further discussion see http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html
Keep changes to spec_helper.rb minimal Put custom configuration under rails_helper.rb
- randomize your tests
- Randomize to catch tests that might be bleeding state into other tests. If your tests randomly fail, look to output of your specs: "Randomized with seed 37226"; Run with
rspec --seed 37226
to rerun the suite with the same conditions.
- Randomize to catch tests that might be bleeding state into other tests. If your tests randomly fail, look to output of your specs: "Randomized with seed 37226"; Run with
- load custom support classes and modules
- configure RSpec and extras like Devise, DatabaseCleaner and Warden
- don't clean out Solr and Fedora unless you have to
- unless testing Javascript, prefer Capybara's default driver to Poltergeist, which is slower
- properties
- default permissions
- required properties
- model settings
- tests the fields that are indexer in solr
- special type of model class from Blacklight
- wraps a single document from a set of results returned from solr
- allows us to define methods for fields and any additional logic
- generated in the controller's response to a request
- has three arguments: a solr document (required), an ability which optional or nil, and an optional ActionDispatch::Request request context
- contains all the logic and metadata to render a page, such as fields, formatting, and additional presenters for contained resources
- most commonly used are the Sufia::WorkShowPresenter and Sufia::FileSetPresenter
- leverage Hydra::Editor capabilities from the hydra-editor gem
- handle translations of input from the parameters hash to values assigned to the object
- validates input
- defines the fields that you're allowed to edit, required fields, default values
- can also instantiate other presenters that are needed to render the edit page
- gets generated with a CC concern or by Sufia
- a class type in CurationConcerns that performs update and create actions on models
- multiple actors are grouped into an "actor stack" that perform these actions in a specified order
- existing actors can be overridden to perform additional actions OR
- new actors can be added to the stack at a specific location in the order
- Note: this must be done via the Sufia::ActorFactory service in Sufia or CurationConcerns::Actors::ActorFactory in CurationConcerns
- standard RSpec tests are used here
- Sufia and CurationConcerns' controllers set presenter and form classes, as well as curation concern types, so it's a good idea to test that here
sample_show_view_spec.rb sample_edit_view_spec.rb
- you'll generally mock and stub everything as opposed to creating objects
- show and index views will have presenters and solr documents
- edit views will need forms
- conforms to the ActiveJob syntax
- one principle method:
perform
which can be tested by callingperform_now
- similar to a service object architecture but with a messaging queue
queue_as
specifies the messaging service, i.e. Resque, SideKick, RabbitMQ, etc.
simple_service_spec.rb hydra_service_spec.rb
- similar to jobs but without the messaging service
- one class performs one task, usually performed with
.call
- good for performing complex tasks
- self-contained and easily testable
- can be invoked from anywhere, even within a job!
- use the built-in
helper
method - mock/stub as needed
- construct in Blacklight that organizes solr search behaviors into composable units
- assists with building a solr query
- assigned by a Blacklight-enabled controller, but can be used anywhere
- testing checks the solr query syntax but not the search results themselves
Home page feature test Sample messaging test Using different sessions
- executes the real page
- use Capybara matchers
- use Rails path helpers
- don't mock (generally) and instead create objects for your tests
- you may have to clean out the repository before each test
- keep the tests "long" because setup and tear-down for each test can be costly
- prefer Capybara's default driver over Poltergeist unless you need to explicitly test Javascript
- off-load as much Javascript testing to Jasmine (see below)
- Use Jasmine to run unit tests for your Javascript files
- Use Poltergeist-enabled feature tests for integration testing
- ECMA6 is the preferred Javascript language style, but JQuery-type plugins or other styles are fine
Install the components
bundle exec rails g jasmine:install
Run the CI tests
bundle exec rake jasmine:ci
Or, startup a web browser to run tests and debug
bundle exec rake jasmine
Then visit http://localhost:8888 and it will run the tests when the page loads. If you want to enable debugging,
open the web inspector console in the browser and reload the page. This will re-run the tests and stop at
any breakpoints identified with debugger
in the JS code.
If you want Jasmine to run its tests when you run RSpec, as part of the test suite, you'll need to use a RSpec test that calls Jasmine and essentially parses its output to look for failures.
- catch-all for non-Rails related classes
- does not include any of RSpec's helper methods:
get
,show
etc. which are used in controllersrendered
from viewshelper
from helpers
- test classes
- helper methods
- any other supplemental code