Get an overview of all the matchers that are built into RSpec Show archive.org snapshot .
Play with some of these matchers in your MovieDB tests.
Which of the following two lines is better? Why?
expect(array).to include(5)
expect(array.include?(5)).to eq(true)
Write a
custom matcher
Show archive.org snapshot
called have_same_attributes_as
. It should compare the attributes of two ActiveRecord instances:
movie1 = create(:movie, title: 'Foo', year: 2007, description: 'Lorem ipsum')
movie2 = create(:movie, title: 'Foo', year: 2007, description: 'Lorem ipsum')
movie3 = create(:movie, title: 'Bar', year: 2008, description: 'Lorem ipsum')
expect(movie1).to have_same_attributes_as(movie2)
# passes
expect(movie1).to have_same_attributes_as(movie3)
# Fails with 'Expected movie #112 to have same attributes as movie #113, but the attributes #title and #year differed'
Now write a method Movie#copy
in your MovieDB. It saves a duplicate of the movie, copying all the attributes. Test this method using your new have_same_attributes_as
matcher.
Tip
ActiveSupport gives your arrays a
#to_sentence
method that may help you build the error message:['foo', 'bar', 'baz'].to_sentence => "foo, bar and baz"
Also see Where to put custom matchers and other support code.
You should know the following tools:
before(:each)
after(:each)
let
subject
RSpec.configure
, config.before
, config.after
Make the following change to your MovieDB:
A new tab "Changes" shows a log of recent changes made to movies and actors.
E.g. when a movie was created there is a log entry saying
Movie "Sunshine" was created
E.g. when a movie was updated there is a log entry saying
Movie "Sunshine" was updated
E.g. when an actor was destroyed there is a log entry saying
Actor "Shohreh Aghdashloo" was destroyed
Use callbacks Show archive.org snapshot to automatically write changelog entries to the database as a model record gets created, updated or destroyed.
Extract the logic into a module
so it can be re-used by both Actor
and Movie
models.
Tip
The method producing the logged identifier may differ between models, e.g.
Actor#full_name
vs.Movie#title
. You can either use the same method name here (like#to_s
or#name_for_log
), or build a parametrized module using Modularity Show archive.org snapshot .
In your RSpec tests, use a shared example group to share tests between actor_spec.rb
and movie_spec.rb
.
Sharing test setup can lead to DRY, but tightly coupled test code. Read Prefer self-contained examples Show archive.org snapshot for an argument for isolating tests instead, even if it means some duplication. In general it is more important for a test to be simple than to be DRY.
A sweet spot is often to prefer isolated tests where possible, but share test setup when it becomes excessively complicated or expensive. If we share setup, it is best to do within a shared context
only. This way so we limit the setup's scope.
describe Klass do
describe '#foo' do
it 'does basic thing 1' do
# isolated test without shared setup here
end
it 'does basic thing 2' do
# isolated test without shared setup here
end
context 'on the night of DST change in Australia' do
before :each do
# complicated, shared setup here
end
it 'handles special case 3' do
# test using the shared setup
end
it 'handles special case 4' do
# test using the shared setup
end
end
end
end
Through Mocking you can take control of the program under test. This lets you test unmocked code easier.
Earlier in this card you implemented a change log for MovieDB. Change your RSpec tests so they no longer write log entries to the database. Instead use mocks to test that log entries would have been written with the correct attributes.
Talk to your mentor about the pros and cons of mocking:
Until now we have only written "model specs". These are classic "unit tests" where you instantiate an object, call a method and observe its return value or side effects.
Your MovieDB already uses the gem rspec-rails Show archive.org snapshot which has many different types of specs. These help you take a close look at Rails components that are not easily instantiated, such as routes, views or controller actions.
Go through the rspec-rails Show archive.org snapshot docs and get an overview what types of specs are supported.
When your MoviesController#show
cannot find a movie, it currently crashes with ActiveRecord::RecordNotFound
. Change that so instead of crashing, it sets a flash "Movie not found" and redirects to the movie index.
Write a
request spec
Show archive.org snapshot
that takes a close look at MoviesController#show
:
movies/show
is rendered/movies
is returned. The HTTP status 307 is used for the redirect. The movies index shows a flash message.Tip
There is a
render_template()
matcher that helps with test above. To get this matcher, add a gemrails-controller-testing
.
Tip
If you place your spec file in
spec/requests
you don't need thetype: :request
option Show archive.org snapshot .
In the validations card we added a helper to display an error message.
Test that helper with a helper spec Show archive.org snapshot .