I have the functionality of my code working correctly, but need to create an RSpec test that covers it. My routes.rb:
resources :movies do
#member routes for individual ones
get 'find_with_same_director', on: :member
end
# map '/' to be a redirect to '/movies'
root :to => 'movies#index'
My code in movies_controller.rb:
def find_with_same_director
@movie = Movie.find(params[:id])
@movies, check_info = Movie.find_with_same_director(params[:id])
if check_info
flash[:notice] = "'#{@movie.title}' has no director info"
redirect_to movies_path
end
end
The find_with_same_director function in the model, movie.rb:
def self.find_with_same_director(id)
movie = self.find(id)
if !movie.director.blank?
movies = self.where(:director => movie.director).where.not(:id => movie.id)
return movies, false
else
return [], true
end
end
I am trying to write tests that covers the click on the "Find With Same Director" link that calls the function, when the movie that was clicked has a director to show, and when it doesn't. I've written the following tests in movies_controller_spec.rb for each so far:
describe 'find_with_same_director' do
it 'should call the find_with_same_director model method' do
expect(Movie).to receive(:find_with_same_director).with(params[:id])
get :find_with_same_director, id: movie.id
end
context 'movie has a director' do
let!(:movie1) {FactoryGirl.create(:movie, :director => movie.director)}
it do
get :find_with_same_director, id: movie1.id
expect(response).to redirect_to(movie_path(movie1.id))
end
end
context 'movie has no director' do
movie1 = FactoryGirl.create(:movie, :director => nil)
it "should redirect to root" do
get :find_with_same_director, id: movie1.id
expect(response).to redirect_to(/movies)
end
end
end
I have spent hours working on these tests and while they are "covering" the lines when i check the report, the first two return fails. This means I wrote them incorrectly. I want to modify these tests to accurately represent what my controller code is doing and I would really appreciate some help with that. If you're feeling down to it I would also appreciate if you gave advice on writing the rspec test code for the model movie.rb file as well.
The error I get when I isolate the first test:
1) MoviesController find_with_same_director should call the find_with_same_director model method
Failure/Error: expect(Movie).to receive(:find_with_same_director).with(params[:id])
NameError:
undefined local variable or method `params' for #<RSpec::ExampleGroups::MoviesController::FindWithSameDirector:0x000000056b27e0>
The error I get when I isolate the second test:
Failures:
1) MoviesController find_with_same_director movie has a director should redirect to "/movies/28"
Failure/Error: expect(response).to redirect_to(movie_path(movie2.id))
Expected response to be a <redirect>, but was <200>
I kind of understand why the errors are happening, I just don't know a fix for them.
Tests usually run in isolation. Therefore let's look at them one after the other:
Your first spec looks like this:
it 'should call the find_with_same_director model method' do
expect(Movie).to receive(:find_with_same_director).with(params[:id])
get :find_with_same_director, id: movie.id
end
It is important to note that in the context of this test either params
nor movie
do exist because you did define them first. You might want to fix this by creating a movie first:
let(:movie) { FactoryGirl.create(:movie) }
it 'should call the find_with_same_director model method' do
expect(Movie).to receive(:find_with_same_director).with(movie.id)
get :find_with_same_director, id: movie.id
end
Two suggestion:
FactoryGirl
is deprecated for a good reason . It was replaced by FactoryBot
. Please update it. Your second spec:
context 'movie has a director' do
let!(:movie1) { FactoryGirl.create(:movie, :director => movie.director) }
it do
get :find_with_same_director, id: movie1.id
expect(response).to redirect_to(movie_path(movie1.id))
end
end
This spec has two issues. It seems like you assume to find a similar movie and redirect to that movie. But you only create only one movie, there is no other movie to redirect to. And even if it was existing there is no redirect in your controller and because you method returns multiple movies it is unclear which similar movies to redirect to.
Your third spec doesn't create a movie correctly. Once that is fixed, I think the spec will pass.
context 'movie has no director' do
let(:movie) { FactoryGirl.create(:movie, :director => nil) } # <= this creates the movie for the test
it "should redirect to root" do
get :find_with_same_director, id: movie.id
expect(response).to redirect_to(/movies)
end
end
Furthermore, I suggest replacing the find_with_same_director
with a scope and have a look into the documentation of Rspec – especially how controller specs are working and the difference between let
and let!
.
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.