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

Када сам пре неколико недеља преправио пројекат, проводио сам већину времена пишући спецификације. Након писања неколико сличних тест случајева за неке АПИ-је, почео сам да се питам да ли бих могао да се решим великог броја дуплирања.
Стога сам се бацио на читање најбољих пракси за тестове СУШЕЊА (Не понављајте се). И тако сам сазнао за 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
.