Как написать тест RSpec для следующего кода - PullRequest
0 голосов
/ 29 марта 2019

Функциональность моего кода работает правильно, но мне нужно создать тест 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

Функция find_with_same_director в модели, 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

Я пытаюсь написать тесты, охватывающие щелчок по ссылке «Найти с тем же режиссером», которая вызывает функцию, когда у фильма, по которому щелкнули, есть режиссер, который нужно показать, а когда нет.Я написал следующие тесты в 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

Я потратил часы, работая над этими тестами, и пока они «покрывают» строки, когда я проверяю отчет, первыйдва возврата не удаются.Это означает, что я написал их неправильно.Я хочу изменить эти тесты, чтобы они точно представляли, что делает код моего контроллера, и я был бы очень признателен за помощь.Если вам не по себе, я также был бы признателен, если бы вы дали совет по написанию тестового кода rspec для файла модели movie.rb.

Ошибка, возникающая при выделении первого теста:

  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>

Я вроде понимаю, почему происходят ошибки, я просто не знаю, как их исправить.

1 Ответ

1 голос
/ 29 марта 2019

Тесты обычно проводятся изолированно.Поэтому давайте посмотрим на них один за другим:

Ваша первая спецификация выглядит следующим образом:

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

Два предложения:

  1. FactoryGirl устарело по веской причине .Его заменили на FactoryBot.Пожалуйста, обновите его.
  2. 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

Кроме того, я предлагаю заменить find_with_same_director областью видимости и взглянуть на документацию по Rspec - особенно, как работают спецификации контроллера иразница между let и let!.

...