ruby-on-rails - 如何为以下代码编写 RSpec 测试
问题描述
我的代码功能正常,但需要创建一个涵盖它的 RSpec 测试。我的路线.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'
我在 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
模型movie.rb中的find_with_same_director函数:
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
我正在尝试编写测试,涵盖单击调用该函数的“查找同一导演”链接,单击的电影何时显示导演,何时没有。到目前为止,我已经在 movies_controller_spec.rb 中为每个测试编写了以下测试:
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
我花了几个小时进行这些测试,当我检查报告时它们“覆盖”了这些行,前两个返回失败。这意味着我写错了。我想修改这些测试以准确地表示我的控制器代码正在做什么,我非常感谢一些帮助。如果您对此感到满意,如果您也提供有关为模型 movie.rb 文件编写 rspec 测试代码的建议,我将不胜感激。
隔离第一个测试时出现的错误:
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>
隔离第二个测试时出现的错误:
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>
我有点理解为什么会发生错误,我只是不知道如何解决它们。
解决方案
测试通常是独立运行的。因此,让我们一个接一个地看它们:
您的第一个规范如下所示:
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
重要的是要注意,在此测试的上下文中,要么params
也不movie
存在,因为您确实首先定义了它们。您可能希望通过首先创建电影来解决此问题:
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
两个建议:
FactoryGirl
被弃用是有充分理由的。它被替换为FactoryBot
。请更新它。- IMO 这个规范根本不应该存在,因为它测试了一个内部实现细节。测试应该具体说明方法返回什么或该方法有什么副作用。但是测试不应该测试某事是如何完成的。原因很简单。当您重构该方法时,即使该方法仍返回确切的看似响应,此类测试也会中断。
你的第二个规格:
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
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
此外,我建议用范围替换并查看 Rspec 的文档——尤其是控制器规范的工作方式以及和find_with_same_director
之间的区别。let
let!
推荐阅读
- android - 来自后台应用程序的 Android 屏幕截图
- javascript - 找不到 Django 静态文件 404
- html - 将同一行中的 4 个 div 对齐,边距为 10px
- python - 将用户关联为另一个模型中的外键后的不确定性
- python - 无法在 Mac 上更改 jupyter notebook 的主目录
- c++ - 当再次触发信号时,第二次调用从 Qt Slot 执行的函数时会发生什么?
- jquery - 使用数据表 jquery 进行烧瓶表搜索
- reactjs - 如何渲染 React 的缓存组件?
- python - 通过 QWebEngineHttpRequest (PyQt5) 发布请求
- python - 用字典的总和值初始化 pyomo 参数