Hogyan lehet kiszárítani az RSpec teszteket megosztott példák segítségével

- Adj hat órát, hogy vágjam le a fát, és az első négyet a fejsze megélezésével töltem. - Abraham Lincoln

Amikor néhány hete átalakítottam egy projektet, időm nagy részét specifikációk írásával töltöttem. Miután néhány hasonló tesztesetet írtam egyes API-khoz, azon gondolkodtam, vajon sikerül-e megszabadulnom ettől a sok másolattól.

Szóval belevetettem magam a tesztek SZÁRÍTÁSÁNAK legjobb gyakorlatainak elolvasásába (Ne ismételd meg magad). És így tudtam meg shared examplesés shared contexts.

Esetemben végül megosztott példákat használtam. És íme, amit eddig megtanultam ezek alkalmazásától.

Ha több olyan specifikációja van, amelyek hasonló viselkedést írnak le, akkor célszerűbb felesleges példákat kivonni shared examplesés több specifikációban használni.

Tegyük fel, hogy két modellje van: User és Post , és egy felhasználónak sok bejegyzése lehet. A felhasználóknak meg kell tudniuk nézni a felhasználók listáját és a bejegyzéseket. Indexfelhasználás létrehozása a felhasználókban és a posztvezérlőkben ezt a célt szolgálja.

Először írjon specifikációkat az index művelethez a felhasználói vezérlő számára. Feladata lesz lekérni a felhasználókat és megfelelő elrendezéssel megjeleníteni őket. Ezután írjon annyi kódot, hogy a tesztek sikeresek legyenek.

# 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

Általában bármely vezérlő indexművelete szükség szerint kevés erőforrásból tölti le és összesíti az adatokat. Ezenkívül hozzáadja a lapozást, a keresést, a válogatást, a szűrést és a hatókört.

Végül mindezeket az adatokat HTML, JSON vagy XML segítségével mutatják be a nézeteknek API-k segítségével. Példám leegyszerűsítése érdekében a vezérlők indexműveletei csak lekérik az adatokat, majd nézeteken keresztül mutatják meg őket.

Ugyanez vonatkozik az index műveletre a bejegyzések vezérlőjében:

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

Az RSpec tesztek, amelyek mind a felhasználók, mind a post vezérlő számára írtak, nagyon hasonlóak. Mindkét vezérlőnk van:

  • A válaszkódnak - OK-nak kell lennie
  • Mindkét indexműveletnek megfelelő rész- vagy nézetté kell válnia - esetünkben index
  • Azok az adatok, amelyeket meg szeretnénk jeleníteni, például bejegyzések vagy felhasználók

Szárítsuk meg index műveletünk specifikációit a használatával shared examples.

Hová tegye a megosztott példákat

Szeretnék megosztott példákat elhelyezni a specs / support / shared_examples könyvtárban, hogy az összes shared examplekapcsolódó fájl automatikusan betöltődjön.

Itt olvashat más, gyakran használt konvenciókról, amelyek shared examplesitt találhatók: megosztott példák dokumentációja

Hogyan definiálhatunk megosztott példát

Az indexműveletnek 200 sikerkóddal (OK) kell válaszolnia, és meg kell adnia az indexsablont.

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

A itblokkjain kívül - és a kampók előtt és után - hozzáadhat letblokkokat, összefüggéseket és leírhatja a blokkokat, amelyek belül is meghatározhatók shared examples.

Én személy szerint szívesebben tartom a megosztott példákat egyszerűek és tömörek, és nem adok hozzá összefüggéseket és nem engedem a blokkokat. A shared examplesblokk paramétereket is elfogad, amelyeket az alábbiakban ismertetek.

Hogyan lehet megosztott példákat használni

Ha hozzáadod include_examples "index examples"a felhasználókhoz és közzéteszed a vezérlő specifikációit, az index-példákat is tartalmaz a tesztekhez.

# 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

Használhatja it_behaves_likevagy it_should_behaves_likehelyett is include_examplesebben az esetben. it_behaves_likeés it_should_behaves_likevalójában álnevek, és ugyanúgy működnek, így felcserélhetők. De include_examplesés it_behaves_likemások.

A hivatalos dokumentációban leírtak szerint:

  • include_examples - példákat tartalmaz a jelenlegi helyzetben
  • it_behaves_likeés it_should_behave_likea példákat beágyazott kontextusba foglalja

Miért számít ez a megkülönböztetés?

Az RSpec dokumentációja megfelelő választ ad:

Ha többször is beilleszt paraméteres példákat az aktuális kontextusba, felülírhatja a korábbi módszer-definíciókat és az utolsó deklaráció nyer.

Tehát amikor olyan helyzetbe kerül, amikor a paraméterezett példák olyan módszereket tartalmaznak, amelyek ütköznek más metódusokkal ugyanabban a kontextusban, akkor helyettesítheti include_examplesa it_behaves_likemódszerrel. Ez beágyazott kontextust hoz létre, és elkerüli az ilyen jellegű helyzeteket.

Nézze meg a következő sort a felhasználói vezérlő specifikációiban és a vezérlő specifikációiban:

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

Most a vezérlő specifikációi tovább feldolgozhatók, ha paramétereket adunk át az alábbi megosztott példának:

# 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

Most végezze el a következő változtatásokat a felhasználókon és a vezérlő specifikációiban:

# 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

Most a vezérlő specifikációi tiszta, kevésbé feleslegesek és ami még fontosabb, SZÁRAZ. Ezen túlmenően ezek az indexpéldák alapvető struktúrákként szolgálhatnak más vezérlők indexműveletének tervezéséhez.

Következtetés

A gyakori példák külön fájlba áthelyezésével kiküszöbölheti a duplikációt és javíthatja a vezérlő műveleteinek konzisztenciáját az alkalmazás során. Ez nagyon hasznos API-k tervezése esetén, mivel az RSpec tesztek meglévő struktúráját felhasználhatja tesztek tervezésére és API-k létrehozására, amelyek betartják a közös válaszstruktúrát.

Leginkább akkor, amikor API-kkal dolgozom, shared examplesközös struktúrát biztosítok számomra a hasonló API-k tervezéséhez.

Nyugodtan ossza meg, hogyan szárítja fel a specifikációit a használatával shared examples.