简体   繁体   English

如何为以下代码编写RSpec测试

[英]How to write RSpec test for the following code

I have the functionality of my code working correctly, but need to create an RSpec test that covers it. 我的代码功能正常运行,但是需要创建一个涵盖它的RSpec测试。 My routes.rb: 我的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: 我在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: 模型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

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: 到目前为止,我已经为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

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. 如果您不满意,也请提供有关为模型movie.rb文件编写rspec测试代码的建议,我也将不胜感激。

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. 重要的是要注意,在此测试的上下文中, paramsmovie都不存在,因为您确实先定义了它们。 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: 两个建议:

  1. FactoryGirl is deprecated for a good reason . FactoryGirl被淘汰是有充分理由的 It was replaced by FactoryBot . 它由FactoryBot代替。 Please update it. 请更新。
  2. IMO this spec should not exist at all, because it tests an internal implementation detail. IMO完全不应该存在此规范,因为它测试了内部实现细节。 Tests should specific what a method returns or what side effects the method has. 测试应具体说明方法返回的内容或该方法产生的副作用。 But Test should not test how something is done. 但是测试不应该测试如何完成某件事。 The reason is very simple. 原因很简单。 Such tests would break when you refactor that method even if the method still returns the exact seems response. 当您重构该方法时,即使该方法仍返回确切的似乎响应,此类测试也会中断。

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! 此外,我建议用范围替换find_with_same_director并查看find_with_same_director的文档-特别是控制器规范的工作方式以及letlet!之间的区别let! .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM