Како ИСУШИТИ своје РСпец тестове помоћу заједничких примера

Дајте ми шест сати да посечем дрво, а прва четири ћу оштрити секиру.“ - Абрахам Линколн

Када сам пре неколико недеља преправио пројекат, проводио сам већину времена пишући спецификације. Након писања неколико сличних тест случајева за неке АПИ-је, почео сам да се питам да ли бих могао да се решим великог броја дуплирања.

Стога сам се бацио на читање најбољих пракси за тестове СУШЕЊА (Не понављајте се). И тако сам сазнао за shared examplesи shared contexts.

У мом случају сам на крају користио заједничке примере. И ево шта сам до сада научио од примене ових.

Када имате више спецификација које описују слично понашање, можда би било боље издвојити сувишне примере shared examplesи користити их у више спецификација.

Претпоставимо да имате два модела Усер и Пост , а корисник може имати много постова. Корисници би требало да могу да виде листу корисника и постове. Стварање акције индекса у контролорима корисника и постова ће послужити у ту сврху.

Прво напишите спецификације за вашу акцију индекса за контролер корисника. Биће одговоран за преузимање корисника и њихово приказивање са правилним распоредом. Затим напишите довољно кода да би тестови прошли.

# users_controller_spec.rbdescribe "GET #index" do before do 5.times do FactoryGirl.create(:user) end get :index end it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) } it { expect(assigns(:users)).to match(User.all) }end
# users_controller.rbclass UsersController < ApplicationController .... def index @users = User.all end ....end

Типично, радња индекса било ког контролора преузима и агрегира податке из неколико ресурса по потреби. Такође додаје пагинацију, претраживање, сортирање, филтрирање и опсег.

Коначно, сви ови подаци су представљени приказима путем ХТМЛ-а, ЈСОН-а или КСМЛ-а помоћу АПИ-ја. Да поједноставим мој пример, индексне акције контролора ће само дохватити податке, а затим их приказати путем погледа.

Исто важи и за акцију индекса у контролору постова:

describe "GET #index" do before do 5.times do FactoryGirl.create(:post) end get :index end it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) } it { expect(assigns(:posts)).to match(Post.all) }end
# posts_controller.rbclass PostsController < ApplicationController .... def index @posts = Post.all end ....end

РСпец тестови написани и за кориснике и за контролоре постова су врло слични. У оба контролера имамо:

  • Шифра одговора - треба да буде „ОК“
  • Обе акције индекса треба да приказују правилно делимично или приказ - у нашем случају index
  • Подаци које желимо да прикажемо, попут постова или корисника

СУХИМО спецификације за нашу акцију индекса користећи shared examples.

Где сместити своје заједничке примере

Волим да дељене примере смештам у директоријум спецс / суппорт / схаред_екамплес тако да се све shared exampleповезане датотеке аутоматски учитавају.

Можете прочитати о другим уобичајеним конвенцијама за проналажење вашег shared examplesовде: документација о дељеним примерима

Како дефинисати заједнички пример

Ваша акција индекса треба да одговори са кодом успеха 200 (у реду) и да прикаже ваш образац индекса.

RSpec.shared_examples "index examples" do it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) }end

Осим itблокова - и пре и после кука - можете додати letблокове, контекст и опис блокова, који такође могу бити дефинисани изнутра shared examples.

Лично више волим да дељени примери буду једноставни и сажети и не додајем контекст и не дозвољавам блокаде. shared examplesБлок такође прихвата параметре, које ћу покривају испод.

Како се користе дељени примери

Додавање include_examples "index examples"спецификација за кориснике и постове контролера укључује „примере индекса“ за ваше тестове.

# users_controller_spec.rbdescribe "GET #index" do before do 5.times do FactoryGirl.create(:user) end get :index end include_examples "index examples" it { expect(assigns(:users)).to match(User.all) }end
# similarly, in posts_controller_spec.rbdescribe "GET #index" do before do 5.times do FactoryGirl.create(:post) end get :index end include_examples "index examples" it { expect(assigns(:posts)).to match(Post.all) }end

Такође можете користити it_behaves_likeили it_should_behaves_likeуместо include_examplesу овом случају. it_behaves_likeи it_should_behaves_likeзаправо су псеудоними и раде на исти начин, тако да се могу користити наизменично. Али include_examplesи it_behaves_likeразличити су.

Као што је наведено у званичној документацији:

  • include_examples - укључује примере у тренутном контексту
  • it_behaves_likeи it_should_behave_likeукључују примере у угнежђени контекст

Зашто је ово разликовање важно?

РСпецова документација даје тачан одговор:

Када више пута укључите параметризоване примере у тренутни контекст, можете заменити претходне дефиниције метода и победе последње декларације.

Дакле, када се суочавају са ситуацијом у којој параметризовани примери садрже методе које су у супротности са другим методама у истом контексту, можете заменити include_examplesса it_behaves_likeметодом. Ово ће створити угнежђени контекст и избећи овакве ситуације.

Погледајте следећи ред у спецификацијама вашег корисничког контролера и објавите спецификације контролера:

it { expect(assigns(:users)).to match(User.all) }it { expect(assigns(:posts)).to match(Post.all) }

Сада се спецификације вашег контролера могу даље преправљати прослеђивањем параметара заједничком примеру као доле:

# specs/support/shared_examples/index_examples.rb
# here assigned_resource and resource class are parameters passed to index examples block RSpec.shared_examples "index examples" do |assigned_resource, resource_class| it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) } it { expect(assigns(assigned_resource)).to match(resource_class.all) }end

Сада направите следеће промене у спецификацијама корисника и постова контролора:

# users_controller_spec.rbdescribe "GET #index" do before do ... end include_examples "index examples", :users, User.allend
# posts_controller_spec.rbdescribe "GET #index" do before do ... end include_examples "index examples", :posts, Post.allend

Сада спецификације контролера изгледају чисто, мање сувишно и што је још важније, СУВО. Даље, ови примери индекса могу послужити као основне структуре за дизајнирање акције индекса других контролера.

Закључак

Премештањем уобичајених примера у засебну датотеку можете елиминисати дуплицирање и побољшати доследност радњи контролера у целој апликацији. Ово је врло корисно у случају дизајнирања АПИ-ја, јер постојећу структуру РСпец тестова можете користити за дизајнирање тестова и креирање АПИ-ја који се придржавају ваше уобичајене структуре одговора.

Углавном, када радим са АПИ-има, shared examplesпружам ми заједничку структуру за дизајнирање сличних АПИ-ја.

Слободно поделите како СУШИТЕ спецификације користећи shared examples.