Kuigi Codest on peamiselt Ruby pood, on üks paljudest projektidest, mida me ehitame, JavaScript. See on kliendipoolne raamatukogu, mis töötab üsna keerulises keskkonnas: see peab toetama peaaegu kõiki olemasolevaid brausereid, sealhulgas väga vanu, ning lisaks sellele suhtleb see veel hulga väliste skriptide ja teenustega. See on tohutult lõbus.
Kummaline juhtum mittekomplektsete sõltuvuste puhul
Ülaltoodud nõuetega kaasneb terve rida väljakutseid, mida tavaliselt kliendipoolses süsteemis ei esine. projektja üks nende küsimuste klass on seotud testimisega. Loomulikult on meil laitmatu hulk ühikteste ja me jooksutame neid oma CI/CD-keskkonnas väga suure hulga brauserite / operatsioonisüsteemide kombinatsioonide vastu, kuid see üksi ei uuri kõike, mis võib valesti minna.
Tulenevalt ökosüsteemi üldisest arhitektuurist, milles me tegutseme, sõltume sellest, et mõned välised raamatukogud laaditakse koos meie omadega - see tähendab, et me ei pakenda neid koos meie kood; me ei saa ja selle vastu pole midagi teha. See kujutab endast huvitavat väljakutset, sest need raamatukogud:
- ei pruugi olla isegi olemas - kui keegi segab meie raamatukogu rakendamist,
- võib olla olemas, kuid vales/mittesobivates versioonides,
- võib olla muudetud mõne muu koodiga, mis on konkreetses rakenduses kaasas.
See näitab selgelt, miks ühiktestidest ei piisa: nad testivad reaalsest maailmast isoleeritult. Ütleme, et me mockime mõne välise raamatukogu avaliku API mingi osa, tuginedes sellele, mida me oleme avastanud selle dokumentides, ja käivitame selle vastu ühiktesti. Mida see tõestab?
Teil võib tekkida kiusatus öelda, et "see tähendab, et see töötab koos välise raamatukogu APIga", kuid te oleksite - kahjuks - valesti. See tähendab ainult seda, et see suhtleb korrektselt välise raamatukogu avaliku API alamhulgaga, ja isegi siis ainult selle versiooniga, mida me oleme jäljendanud.
Mis siis, kui raamatukogu muutub sõna otseses mõttes meie alt ära? Mis siis, kui see saab - seal looduses - mingeid kummalisi vastuseid, mis panevad selle sattuma teistsugusele, dokumenteerimata koodipolgule? Kas me saame selle eest üldse kaitsta?
Mõistlik kaitse
Mitte 100%, ei - keskkond on selleks liiga keeruline. Kuid me saame olla mõistlikult kindlad, et kõik töötab nii, nagu see peaks toimima, kasutades mõningaid üldistatud näiteid selle kohta, mis meie koodiga võib looduses juhtuda: me saame teha integratsioonitestimist. Ühiktestid tagavad, et meie kood töötab sisemiselt korralikult, ja integratsioonitestid peavad tagama, et me "räägime" korralikult raamatukogudega, mida me ei saa kontrollida. Ja ka mitte nende tüvedega - tegelike, elusate raamatukogudega.
Me võiksime lihtsalt kasutada ühte olemasolevatest integratsioonitesti raamistikest, et JavaScript, ehitame lihtsa HTML-lehe, esitame mõned kutsed meie raamatukogule ja kaugeleulatuvatele raamatukogudele ning anname sellele korraliku treeningu. Me ei taha aga üle ujutada ühtegi kaugteenuse lõpp-punkti meie CI/CD-keskkonna poolt genereeritud üleskutsetega. See segaks mõningaid statistilisi andmeid, võib-olla rikuks mõned asjad, ja - viimaks, kuid mitte vähemtähtsaks - me ei oleks väga tore, kui me teeksime kellegi toodangu meie testide osaks.
Aga kas integratsioonitestimine oli üldse võimalik? Kuna Ruby on meie esimene ja peamine armastus, siis toetusime oma teadmistele ja hakkasime mõtlema, kuidas me tavaliselt Ruby projektides kaugteenustega integratsioonitestimist teeme. Me võiksime kasutada midagi sellist nagu vcr gem, et salvestada kord toimuvat, ja siis jätkata selle taasesitamist meie testidele, kui see on vajalik.
Sisestage proxy
Vcr saavutab selle sisemiselt taotluste vahendamise teel. See oli meie a-ha! hetk. Me pidime iga päringu, mis ei tohiks "päris" internetis midagi tabada, proxy'ga edasi suunama mõnele stubed responses'ile. Siis antakse need sissetulevad andmed edasi välisele raamatukogule ja meie kood töötab nagu tavaliselt.
Kui prototüüpimine tundub keeruline, kasutame sageli Ruby't kui aja kokkuhoiu meetodit. Otsustasime teha meie JavaScript jaoks prototüübi testvaljuse Ruby's, et näha, kui hästi proxy idee töötab, enne kui võtame kohustuse ehitada midagi keerulisemat (võimalik, et) JavaScript's. See osutus üllatavalt lihtsaks. Tegelikult on see nii lihtne, et me ehitame selle artikli raames üheskoos ühe 🙂 .
Valgus, kaamera... oota, me unustasime rekvisiidid!
Loomulikult ei tegele me "päris asjaga" - isegi natuke sellest, mida me ehitame, selgitamine ületab kaugelt ühe blogipostituse ulatuse. Me saame ehitada midagi kiiret ja lihtsat, mis seisab kõnealuste raamatukogude eest ja siis keskenduda rohkem Ruby osale.
Kõigepealt on meil vaja midagi, mis asendaks välist raamatukogu, millega me tegeleme. Meil on vaja, et see näitaks paari käitumist: see peaks võtma ühendust välise teenusega, kiirgama siin ja seal sündmust ning - mis kõige tähtsam - ei peaks olema ehitatud lihtsat integreerimist silmas pidades 🙂 .
Siin on see, mida me kasutame:
=
= .= {
: () {
= ().= .(, , )
= (). = () {
(.=== 4) {
(.=== 200) {
.=.} {
.=
}.()
}
}.().()
},
: ,
: {}
}
Sa märkad, et see kutsub avatud API-d mõnede andmete jaoks - antud juhul mõned krüptovaluuta vahetuskursid, kuna see on tänapäeval kogu raevu See API ei eksponeeri liivakasti ja see on rate-limited, mis teeb sellest suurepärase näite millestki, mida ei tohiks tegelikult testides tabada.
Te võite märgata, et see on tegelikult NPM-ühilduv moodul, samas kui ma vihjasin sellele, et skript, millega me tavaliselt tegeleme, ei ole NPM-is saadaval, et seda saaks hõlpsasti komplekteerida. Selle demonstratsiooni jaoks piisab sellest, et see näitab teatud käitumist, ja ma tahaksin siin pigem lihtsustada seletamist liigse lihtsustamise hinnaga.
Näitlejate kutsumine
Nüüd on meil vaja ka midagi, mis asendaks meie raamatukogu. Jällegi hoiame nõuded lihtsad: see peab kutsuma meie "välist" raamatukogu ja tegema midagi väljundiga. Selleks, et hoida "testitav" osa lihtsana, laseme tal teha ka kahekordset logimist: nii konsooli, mida on natuke raskem lugeda spetsifikatsioonides, kui ka globaalselt saadaval olevasse massiivi.
.= ().= .= []
() {..().()
}.(, () {
(..) {
([]).=
} {
()
([] : ${....})
}
})..()
Ma hoian ka käitumise meelega hämmastavalt lihtsana. Nii nagu see on, on ainult kaks tegelikult huvitavat koodirada, mille jaoks spetsifitseerida, nii et me ei jää spetsifikaatide laviini alla, kui me ehitamise käigus edasi liigume.
See kõik lihtsalt klapib kokku
Viskame üles lihtsa HTML-lehe:
<> <! >
<>
<>
<></>
< = =></>
</>
<></>
</>
Selle demo tarbeks ühendame oma HTML ja JavaScript koos Pakett, väga lihtne veebirakendus komplekteerija. Mulle meeldib Parcel väga sellistel puhkudel, kui ma viskan kokku kiire näite või häkkisin mingi klassiidee. Kui teed midagi nii lihtsat, et Webpacki konfigureerimine võtaks rohkem aega kui soovitud koodi kirjutamine, on see parim.
See on ka piisavalt tagasihoidlik, et kui ma tahan vahetada midagi, mis on natuke rohkem lahingukatsetatud, ei pea ma tegema peaaegu mingit tagasilööki Parcelist, mida ei saa öelda Webpacki kohta. Märkus ettevaatust, aga - Parcel on raske arengu ja probleemid võivad ja ilmnevad; mul on olnud probleem, kus transpiled JavaScript väljund oli kehtetu vanemal Node.js. Lõpptulemus: ärge tehke seda veel oma tootmisprotsessi osaks, kuid proovige seda sellegipoolest.
Integratsiooni võimsuse rakendamine
Nüüd saame koostada oma testivalmisprogrammi.
Spetsifikaadi raamistiku enda jaoks kasutasime rspec. Arenduskeskkondades testime, kasutades tegelikku, mitteheadless Chrome'i - selle käivitamise ja kontrollimise ülesanne on langenud watir (ja selle usaldusväärne abiline watir-rspec). Meie proxy jaoks oleme kutsunud Puffing Billy ja rack peole. Lõpuks tahame oma JavaScript ehitust iga kord uuesti käivitada, kui käivitame spetsifikatsioonid, ja see saavutatakse järgmiselt. kokaiin.
See on terve hulk liikuvaid osi ja seega on meie spetsifitseerimise abimees isegi selles lihtsas näites mõnevõrra... kaasatud. Vaatame seda ja võtame selle lahti.
Enne kogu komplekti käivitame oma kohandatud ehituskäsu läbi kokaiini. See konstant TEST_LOGGER võib olla natuke üle jõu käiv, kuid me ei ole siin väga mures objektide arvu pärast. Loomulikult käivitame specs'id juhuslikus järjekorras ja meil on vaja lisada kõik watir-rspec'i head asjad. Samuti peame seadistama Billy nii, et see ei teeks vahemälu, kuid ulatuslik logimine toimub spec/log/billy.log
. Kui te ei tea, kas päring on tegelikult peatunud või tabab live-serverit (hups!), siis on see logi puhas kuld.
Olen kindel, et teie terav silm on juba märganud ProxySupport ja BrowserSupport. Sa võid arvata, et meie kohandatud maiuspalad istuvad seal... ja sul oleks täpselt õigus! Vaatame kõigepealt, mida BrowserSupport teeb.
Brauser, kontrollitud
Esmalt tutvustame TempBrowser
:
Töötades tagasi läbi kõnepuu, näeme, et me seadistame Seleniumi brauseri valikute komplekti Chrome'ile. Üks valikuid, mida me sinna edastame, on meie seadistuses oluline: see annab Chrome'i instantsile korralduse edastada kõik meie Puffing Billy instantsi kaudu. Teine valik on lihtsalt tore - iga instants, mida me käivitame, mis ei ole peata avanevad kontrollivahendid automaatselt. See säästab meid lugematul hulgal Cmd+Alt+I'd päevas 😉.
Pärast seda, kui oleme seadistanud brauseri nende valikutega, edastame selle Watirile ja see ongi enam-vähem kõik. Veebileht tappa
meetod on natuke suhkrut, mis võimaldab meil vajaduse korral draiverit korduvalt peatada ja taaskäivitada, ilma et TempBrowser'i instantsi ära visata.
Nüüd saame anda meie rspec näidetele paar supervõimet. Esiteks, me saame nutikaid brauser
abimeetod, mille ümber meie spetsifikatsioonid enamasti keerlevad. Me saame kasutada ka praktilist meetodit, et taaskäivitada brauser konkreetse näite jaoks, kui me teeme midagi ülitundlikku. Loomulikult tahame ka brauseri pärast testikomplekti lõpetamist tappa, sest me ei taha mitte mingil juhul, et Chrome'i instantsid jääksid püsima - meie RAM-i huvides.
Proxy ühendamine
Meil on loodud brauser ja spetsiifilised abimehed ning me oleme valmis alustama päringute edastamist meie proksile. Aga oodake, me ei ole seda veel seadistanud! Me võiksime iga näite jaoks korduvaid kutsungeid Billyle paugutada, kuid parem on hankida endale paar abimeetodit ja säästa paar tuhat klahvivajutust. See ongi see, mida ProxySupport
teeb.
See, mida me kasutame oma testseadistuses, on veidi keerulisem, kuid siin on üldine idee:
Me võime torkida:
- HTML-lehe taotlused - meie peamise "mänguväljaku" lehe jaoks,
- JS taotlused - meie komplekteeritud raamatukogu teenindamiseks,
- JSON-päringud - taotluse esitamiseks kaugele API-le,
- ja lihtsalt "mis tahes" taotlus, mille puhul meid huvitab ainult konkreetse, mitte-200 HTTP-vastuse tagastamine.
See sobib meie lihtsa näite jaoks hästi. Näidetest rääkides - me peaksime looma paar!
Hea külje testimine
Me peame kõigepealt ühendama paar "marsruuti" meie proxy jaoks:
Tasub märkida, et rspec'i seisukohalt viitavad suhtelised teed siin projekti põhikataloogile, seega laadime oma HTML-i ja JS-i otse kataloogist dist
kataloogi - nagu on ehitatud Parcel'i poolt. Saate juba näha, kuidas need stub_*
abilised tulevad kasuks.
Samuti tasub märkida, et me paigutame oma "võltsitud" veebilehe kohta .local
TLD. Sel viisil ei tohiks meie kohalikust keskkonnast väljuda ühtegi väljapääsmatut taotlust, kui midagi läheb halvasti. Üldise tavana soovitaksin vähemalt mitte kasutada "päris" domeeninimesid stubides, kui see pole absoluutselt vajalik.
Teine märkus, mille me peaksime siinkohal tegema, on see, et me ei tohi ennast korrata. Kuna proxy marsruutimine muutub keerulisemaks, palju rohkemate teede ja URL-idega, on selle seadistuse väljavõtmine jagatud konteksti ja selle lihtne kaasamine vajaduse korral tõelist väärtust.
Nüüd saame täpsustada, kuidas meie "hea" tee peaks välja nägema:
See on üsna lihtne, kas pole? Veel mõned seadistused siin - stubime JSON-vastuse kaug-API-st koos kinnitusega, läheme meie peamisele URLile ja siis... ootame.
Pikim ooteaeg
Ootused on viis, kuidas ümber käia piiranguga, millega me oleme Watiriga kokku puutunud - me ei saa usaldusväärselt oodata näiteks JavaScript sündmusi, seega peame natuke petma ja "ootama", kuni skriptid on liigutanud mõne objekti, millele meil on juurdepääs, meile huvipakkuvasse olekusse. Miinuseks on see, et kui seda olekut ei tule kunagi (näiteks vea tõttu), siis peame ootama, et watir waiter aeg maha võtaks. See ajab spec aega natuke üles. Spekter siiski usaldusväärselt ebaõnnestub.
Pärast seda, kui leht on "stabiliseerunud" meile huvipakkuvas olekus, saame sooritada veel mõned JavaScript lehekülje kontekstis. Siinkohal kutsume üles avalikku massiivi kirjutatud logid ja kontrollime, kas need on need, mida me ootasime.
Kõrvalmärkusena - siinkohal paistab kaugjuhtimispäringu stubbing tõesti silma. Vastus, mis konsooli logitakse, sõltub kaugjuhtimisplatvormi poolt tagastatud vahetuskursist, nii et me ei saaks usaldusväärselt testida logi sisu, kui see pidevalt muutuks. Loomulikult on võimalusi selle vältimiseks, kuid need ei ole väga elegantsed.
Halva haru testimine
Veel üks asi, mida testida: "ebaõnnestumise" haru.
See on väga sarnane ülaltooduga, erinevus seisneb selles, et me tagastame vastuseks HTTP-koodi 404 ja ootame teistsugust logi.
Käivitame nüüd meie spetsifikatsioonid.
Woohoo!
Kokkuvõte
Me arutasime lühidalt, kuidas JavaScript saab integreerimist testida koos Ruby'ga. Kuigi algselt peeti seda pigem vahepealseks, oleme nüüd oma väikese prototüübiga üsna rahul. Loomulikult kaalume endiselt puhta JavaScript lahenduse loomist, kuid vahepeal on meil lihtne ja praktiline viis, kuidas reprodutseerida ja testida mõningaid väga keerulisi olukordi, millega oleme looduses kokku puutunud.
Kui te kaalute midagi sarnast ise ehitada, tuleb märkida, et see ei ole ilma piiranguteta. Näiteks kui teie testimine muutub väga AJAX-rohke, võtab Puffing Billy-l vastamine kaua aega. Samuti, kui teil on vaja mõned SSL-allikaid kasutada, on vaja veel veidi rohkem fiktsioone - vaadake watiri dokumentatsiooni, kui see on teie nõue. Kindlasti jätkame uurimist ja otsime parimaid viise meie unikaalse kasutusjuhtumi lahendamiseks - ja anname kindlasti ka teile teada, mida me välja leidsime.