Testiranje od konca do konca z Joomlo! in Cypress - Moji prvi koraki in misli

Avtomatski testi niso posebno orodje za razvijalce programske opreme v velikih projektih. Zlasti pri razširitvah so avtomatizirani testi pomoč pri hitrem prepoznavanju težav. Pomagajo zagotoviti nemoteno delovanje razširitev v novejših različicah Joomla.

Razvijalci Joomla Core želijo, da razvijalci programske opreme tretjih oseb testirajo njihove razširitve, da najdejo napake, preden jih najde uporabnik. To zahteva veliko časa in je dolgočasno delo. Zato se pogosto ne opravi. Še posebej ne, če je treba ročno s strani ljudi za vsako novo izdajo. Avtomatizirano testiranje omogoča ponovitev ročnih korakov za vsako izdajo, ne da bi jih izvajal človek sam. Na ta način se napake najdejo, preden uporabnik naleti nanje, ko dostopa do živega sistema.

Mimogrede, vsakdo, ki želi preveriti Cypress, bo našel to besedilo kot dober začetek. Težave lahko testirate, ne da bi morali vse namestiti in konfigurirati sami. V repozitoriju Github projekta Joomla je vse pripravljeno.

uvod

»Čeprav je res, da kakovosti ni mogoče preizkusiti, je prav tako očitno, da brez testiranja ni mogoče razviti ničesar kakovostnega.« – [James A. Whittaker]

Preden sem prvič srečal Cypress, si nisem mogel predstavljati, da bodo ovire, ki so me pogosto ovirale pri testiranju, dejansko nekoliko odmaknjene. Veliko časa sem porabil za preizkušanje programske opreme – prej pa še več časa za reševanje težav ki je nastal zaradi pomanjkanja testiranja! Zdaj sem prepričan, da testi, ki so:

  • čim bližje časovno programiranju,
  • samodejno,
  • pogosto - idealno po vsaki spremembi programa,

    prinesite več, kot stanejo In še več: testiranje je lahko celo zabavno.

Vredno se je naučiti testnih metod! Testne metode so dolgotrajne, saj jih je mogoče uporabiti ne samo s katerim koli programskim jezikom, ampak jih je mogoče uporabiti pri skoraj vsakem človeškem delu. Skoraj vse, kar je pomembno v življenju, morate preizkusiti občasno. Testne metode so neodvisne od določenih programskih orodij.Za razliko od programskih tehnik ali programskih jezikov, ki so pogosto v modi in izven mode, je znanje o tem, kako postaviti dobre teste, brezčasno.

Kdo naj bere to besedilo?

Vsi, ki mislite, da je preizkušanje programske opreme izguba časa, bi si morali ogledati ta članek. Še posebej bi rad povabil k branju tiste razvijalce, ki so si vedno želeli pisati teste za svojo programsko opremo - vendar nikoli niso počeli za raznovrstne Cypress bi lahko bil način za odstranitev takšnih ovir.

Nekaj ​​teorije

Čarobni trikotnik

Čarobni trikotnik opisuje razmerje med stroški, zahtevanim časom in dosegljivo kakovostjo. Prvotno je bilo to razmerje prepoznano in opisano v vodenju projektov. Vendar ste verjetno slišali za to napetost tudi na drugih področjih. težava v skoraj vseh operativnih procesov v podjetju.

Na primer, na splošno se domneva, da ima višji strošek pozitiven vpliv na kakovost in/ali datum dokončanja - to je čas.

 

Čarobni trikotnik pri projektnem vodenju – Če se v projekt vloži več denarja, to pozitivno vpliva na kakovost ali čas.

Nasprotno pa bo prihranek pri stroških povzročil zmanjšanje kakovosti in/ali zakasnitev dokončanja.

Čarobni trikotnik pri vodenju projektov – Če se v projekt vloži manj denarja, to negativno vpliva na kakovost ali čas.

Zdaj nastopi čarovnija: premagamo korelacijo med časom, stroški in kakovostjo! Ker je na dolgi rok to dejansko mogoče premagati.

Povezavo med časom, stroški in kakovostjo je mogoče premagati na dolgi rok.

Morda ste tudi vi v praksi izkusili, da znižanje kakovosti dolgoročno ne prinese prihranka pri stroških, tehnični dolg, ki nastane zaradi tega, pogosto vodi celo do povečanja stroškov in dodatnega časa.

Dolgoročno je korelacijo med stroški, časom in kakovostjo dejansko mogoče preseči.

Tehnični dolg se nanaša na dodaten trud, vložen pri spreminjanju in izboljšavah slabše programirane programske opreme v primerjavi z dobro napisano programsko opremo. Martin Fowler razlikuje naslednje vrste tehničnega dolga: tistega, v katerega ste vstopili namerno, in tistega, v katerega ste vstopili nehote. Razlikuje tudi med preudarnimi in nepremišljenimi tehničnimi dolgovi.

Tehnični dolg

Stroški in koristi

V literaturi boste našli porazne statistike o možnostih uspeha programskih projektov. Malo se je spremenila negativna slika, ki jo je zabeležila že študija AW Feyhla v 90. letih prejšnjega stoletja. Tukaj je v analizi 162 projektov v 50 organizacijah s , je bilo ugotovljeno stroškovno odstopanje od prvotnega načrta: 70% projektov je pokazalo stroškovno odstopanje vsaj 50%! Nekaj ​​ni v redu! S tem se ne moreš kar sprijazniti, kajne?

Ena od rešitev bi bila, da bi popolnoma opustili ocene stroškov in sledili argumentaciji gibanja #NoEstimates . To gibanje meni, da so ocene stroškov v projektu programske opreme nesmiselne. Projekt programske opreme po mnenju #NoEstimates vedno vsebuje produkcijo novega.Novo ni primerljivo z že obstoječimi izkušnjami in zato ni predvidljivo.

Več izkušenj pridobivam, bolj prihajam do zaključka, da ekstremni pogledi niso dobri. Rešitev je skoraj vedno na sredini. Izogibajte se ekstremom tudi pri programskih projektih in iščite sredino. Ni treba imeti 100% prepričan načrt. Toda prav tako ne smete začeti novega projekta naivno. Čeprav je vodenje projektov programske opreme in še posebej ocena stroškov pomembna tema, vas v tem besedilu ne bom več dolgočasil s tem. Poudarek tega članka je pokazati, kako E2E testiranje je mogoče vključiti v praktični potek dela pri razvoju programske opreme.

Integrirajte testiranje programske opreme v svoj potek dela

Odločili ste se, da preizkusite svojo programsko opremo. Odlično! Kdaj je najboljši čas za to? Oglejmo si stroške odpravljanja napak v različnih fazah projekta. Prej ko najdete napako, nižji so stroški njene odprave .

Relativni stroški za odpravljanje težav v različnih fazah projekta

Preizkušanje in odpravljanje napak: Obstajajo besede, ki se pogosto omenjajo v isti sapi in katerih pomeni so zato izenačeni. Vendar pa se izraza ob natančnejšem pregledu različno razlagata. Testiranje in odpravljanje napak spadata k tema besedama. Oba izraza imata skupno da zaznavajo okvare, obstajajo pa tudi razlike v pomenu.

  • Testi odkrivajo neznane okvare med razvojem, iskanje okvare je drago, lokalizacija in odprava napake pa poceni.
  • Razhroščevalniki odpravijo napake, ki se odkrijejo, ko je izdelek končan. Iskanje napake je brezplačno, lociranje in odpravljanje napake pa je drago.

Zaključek: Najbolj smiselno je začeti z integracijo testov čim prej, žal je to težko implementirati v odprtokodnem projektu, kot je Joomla, kjer večinoma prostovoljno sodelujejo.

Neprekinjena integracija (CI)
Stalna integracija testov

Predstavljajte si naslednji scenarij. Kmalu bo izdana nova različica priljubljenega sistema za upravljanje vsebin. Vse, kar so razvijalci v skupini prispevali od zadnje izdaje, se zdaj prvič uporablja skupaj. Napetost narašča! deluje? Ali bodo vsi testi uspešni - če projekt sploh vključuje teste. Ali pa bo treba izdajo nove različice znova preložiti in čakajo ure živcev parajočega odpravljanja napak? Mimogrede, preložitev datuma izdaje tudi ni dobro za podobo programskega izdelka! Noben razvijalec ne mara doživeti tega scenarija. Veliko bolje je kadar koli vedeti, v kakšnem stanju je trenutno programski projekt? Kodo, ki se ne ujema z obstoječo, je treba integrirati šele po so bili "made to fit".Zlasti v časih, ko je vedno pogosteje, da je treba odpraviti varnostno vrzel, mora biti projekt vedno sposoben ustvariti izdajo! In tu pride do izraza stalna integracija.

Pri kontinuirani integraciji so posamezni elementi programske opreme trajno integrirani. Programska oprema se ustvarja in testira v majhnih ciklih. Na ta način naletite na težave med integracijo ali napačne teste v zgodnji fazi in ne dni ali tednov kasneje. Z uspešno integracijo, Odpravljanje težav je veliko lažje, ker se napake odkrijejo blizu časa programiranja in je običajno prizadet le majhen del programa. Joomla integrira novo kodo s stalno integracijo. Nova koda se integrira šele, ko so opravljeni vsi testi.

Z nenehno integracijo nove programske opreme je odpravljanje težav veliko lažje, saj se napake odkrijejo blizu časa programiranja in je običajno prizadet le majhen del programa.

Če želite zagotoviti, da imate med neprekinjeno integracijo ves čas na voljo teste za vse dele programa, morate razviti programsko opremo, ki temelji na testiranju.

Testno usmerjen razvoj (TDD)

Testno voden razvoj je tehnika programiranja, ki uporablja razvoj v majhnih korakih. Najprej napišete testno kodo. Šele nato ustvarite programsko kodo, ki jo želite testirati. Vsaka sprememba programa se izvede šele, ko je testna koda za to spremembo opravljena ustvarjen. Torej vaši testi ne uspejo takoj po ustvarjanju. Zahtevana funkcija še ni implementirana v programu. Šele nato ustvarite dejansko programsko kodo - to je programsko kodo, ki zadovolji test.

TDD testi vam pomagajo pravilno napisati program .

Ko prvič slišite za to tehniko, vam koncept morda ne bo najbolj všeč. "Človek" želi navsezadnje najprej narediti nekaj produktivnega. In pisanje testov se na prvi pogled ne zdi produktivno. Preizkusite. Včasih z novo tehniko se spoprijateljiš šele, ko jo spoznaš!V projektih z visoko pokritostjo testov se počutim bolj udobno, ko dodajam nove funkcije.

Če preletite del vaje na koncu besedila, ga lahko preizkusite. Najprej ustvarite test in nato napišite kodo za Joomla Core. Nato vse skupaj oddajte kot PR na Github. Če bi vsi to počeli , Joomla bi imel idealno testno pokritost.

Razvoj, ki temelji na vedenju (BDD)

BDD ni še ena programska tehnika ali tehnika testiranja, ampak nekakšna najboljša praksa za razvoj programske opreme. BDD je idealno uporabljati skupaj s TDD. Načeloma Behaviour-Driven-Development pomeni testiranje ne implementacije programske kode, temveč izvajanje - obnašanje programa S testom se preveri, ali je specifikacija, to je zahteva naročnika, izpolnjena.

Ko razvijate programsko opremo na način, ki temelji na vedenju, vam testi ne pomagajo le pravilno napisati program, temveč vam tudi pomagajo napisati pravi program .

Kaj mislim s tem: "Napišite pravi program"? Zgodi se, da uporabniki vidijo stvari drugače kot razvijalci. Primer je potek dela brisanja članka v Joomli. Vedno znova srečam uporabnike, ki kliknejo ikono stanja v smeti in so presenečeni. Uporabnik običajno intuitivno domneva, da je element zdaj trajno izbrisan, vendar se preklopi iz smeti v aktiviranega. Za razvijalce je klik na ikono stanja sprememba stanja, preklop. v vseh drugih pogledih. Zakaj bi bilo to v košu drugače? Za razvijalca je funkcija implementirana brez napak. Joomla deluje pravilno. Ampak po mojem mnenju funkcija na tem mestu ni prava, ker bi jo večina uporabnikov opisala/zahtevala čisto drugače .

Pri razvoju, ki temelji na vedenju, so zahteve za programsko opremo opisane s primeri, imenovanimi scenariji ali uporabniške zgodbe.

  • močno vključevanje končnega uporabnika v proces razvoja programske opreme,
  • dokumentacijo vseh faz projekta z zgodbami uporabnikov/primeri primerov v besedilni obliki – običajno v opisnem jeziku v opisnem jeziku Gherkin,
  • samodejno testiranje teh uporabniških zgodb/študij primerov,
  • sukcesivna implementacija Tako lahko kadarkoli dostopate do opisa programske opreme, ki jo želite implementirati, s pomočjo katerega lahko nenehno zagotavljate pravilnost že implementirane programske kode.

Projekt Joomla je uvedel BDD v projektu Google Summer of Code . Upali so, da bodo uporabniki brez znanja programiranja lažje sodelovali z uporabo Gherkin .) Pristopa niso dosledno spremljali. Takrat je Joomla uporabljala Codeception kot orodje za testiranje S Cypressom je razvoj BDD mogoče razvijati tudi na način BDD.

Načrtovanje

Vrste testov
  • Enotni testi: Enotni test je test, ki neodvisno testira najmanjše programske enote.
  • Integracijski testi: Integracijski test je test, ki preizkuša interakcijo posameznih enot.
  • E2E testi ali sprejemni testi: Sprejemni test preveri, ali program izpolnjuje nalogo, opredeljeno na začetku.
strategije

Če želite v Joomlo dodati novo funkcijo in jo zavarovati s testi, lahko nadaljujete na dva načina.

Od zgoraj navzdol in od spodaj navzgor sta dva bistveno različna pristopa k razumevanju in predstavitvi kompleksnih vprašanj. Pristop od zgoraj navzdol gre korak za korakom od abstraktnega in splošnega do konkretnega in specifičnega. Če to ponazorimo s primerom: sistem za upravljanje vsebine, kot je Joomla na splošno predstavlja spletne strani v brskalniku.Konkretno pa je v tem procesu nekaj manjših podopravil, ena izmed njih je prikaz določenega besedila v naslovu.

Od spodaj navzgor opisuje nasprotno smer: na tej točki se velja še enkrat spomniti, da je eden od elementov razvoja, ki temelji na vedenju, ustvarjanje besedilnega opisa vedenja programske opreme. Ta opis kriterijev sprejemljivosti pomaga pri ustvarjanju testov - še posebej na vrhu - testi od konca do konca ali sprejemljivi testi.

Običajen pristop k ustvarjanju testov danes je od spodaj. Če imate raje razvoj programske opreme, ki temelji na vedenju, uporabite nasprotno strategijo. Uporabite strategijo od zgoraj navzdol. Pri strategiji od zgoraj navzdol se nesporazum odkrije zgodaj v fazi načrtovanja.

Testne strategije: testiranje od zgoraj navzdol in testiranje od spodaj navzgor

  • Testiranje od zgoraj navzdol: Pri uporabi strategije od zgoraj navzdol se začne s sprejemljivimi testi - tj. z delom sistema, ki je najtesneje povezan z zahtevami uporabnika. Pri programski opremi, napisani za človeške uporabnike, je to običajno uporabniški vmesnik Poudarek je na testiranju, kako uporabnik komunicira s sistemom. Slabost testiranja od zgoraj navzdol je, da je treba porabiti veliko časa za ustvarjanje testnih dvojnikov. Komponente, ki še niso integrirane, je treba zamenjati z ogradami. na začetku ni prave programske kode, zato je treba manjkajoče dele ustvariti umetno, postopoma pa te umetne podatke nadomestijo resnično izračunani podatki.

  • Testiranje od spodaj navzgor: če sledite strategiji od spodaj navzgor, začnete z enotnimi testi. Na začetku ima razvijalec v mislih ciljno stanje, vendar ta cilj nato najprej razdeli na posamezne komponente. Težava z Pristop od spodaj navzgor je, da je težko testirati, kako bo komponenta kasneje uporabljena v realnih situacijah.Prednost testiranja od spodaj navzgor je, da smo zelo hitro končali programske dele, vendar je treba te dele uporabljati previdno. Delujejo pravilno. To zagotavljajo testi enot. Toda ali je končni rezultat res takšen, kot si stranka predstavlja programsko opremo, ni zagotovljeno.

Testna piramida Mikea Cohna

Koliko testov katere vrste testov je treba izvesti? Testna piramida Mikea Cohna opisuje koncept za uporabo avtomatiziranih testov programske opreme. Piramida je sestavljena iz treh ravni, strukturiranih glede na pogostost uporabe in pomembnost. ‍

V idealnem primeru je osnova testne piramide sestavljena iz številnih hitrih in preprostih za vzdrževanje enotnih testov.Na ta način je mogoče večino napak hitro odkriti.

Na srednjem nivoju so integracijski testi, ki zagotavljajo storitve ciljnega testiranja kritičnih vmesnikov, čas izvajanja integracijskih testov je daljši, njihovo vzdrževanje pa je zahtevnejše kot pri enotnih testih.

Vrh piramide sestavljajo počasni E2E testi, ki včasih zahtevajo veliko vzdrževanja.E2E testi so zelo uporabni za testiranje aplikacije kot celotnega sistema.

Zahteve

Kakšno opremo potrebujete za delo na naslednjem praktičnem delu?

Katere zahteve morate imeti za aktivno delo na naslednjem praktičnem delu? Ni vam treba izpolnjevati prav veliko zahtev, da bi lahko delali na vsebini tega priročnika. Seveda morate imeti računalnik. Razvojno okolje z Git, NodeJS in Composer ter lokalni spletni strežnik bi morali biti nameščeni ali jih je mogoče namestiti.

Kakšno znanje morate imeti vi osebno?

Morali bi poznati osnovne tehnike programiranja. V idealnem primeru bi že programirali majhno spletno aplikacijo. V vsakem primeru bi morali vedeti, kam shranite datoteke na vašem razvojnem računalniku in kako jih naložite v internetni brskalnik. ven nove stvari.

Preizkusite. Integrirajte teste v svoj naslednji projekt. Morda vam bo vaša prva izkušnja s testom prihranila dolgočasno sejo odpravljanja napak ali neprijetno napako v resničnem sistemu. Navsezadnje lahko z varnostno mrežo testov razvijete programsko opremo z manj stres.

Nastavitev

Nastavitev Cypress z Joomla!

V različici za razvijalce, ki je na voljo na Githubu, je Joomla konfigurirana za Cypress Ready. Obstajajo že testi, ki jih lahko uporabite kot vodilo. Zato ni treba vse nastaviti sami, da dobite prvi pregled. Tako lahko eksperimentirate s Cypressom , spoznajte njegove prednosti in slabosti ter se sami odločite, ali želite uporabiti testno orodje.

Koraki za nastavitev lokalnega okolja:

Klonirajte repozitorij v koren vašega lokalnega spletnega strežnika:

$ git clone https://github.com/joomla/joomla-cms.git

Pomaknite se do mape joomla-cms:

$ cd joomla-cms

Glede na Joomla Roadmap bo naslednja večja različica 5.0 izdana oktobra 2023. Da bi bil na tekočem, tukaj uporabljam to razvojno različico.

Sprememba v vejo 5.0-dev :

$ git checkout 5.0-dev

Namestite vse potrebne skladateljske pakete:

$ composer install

Namestite vse potrebne pakete npm:

$ npm install

Za več informacij in pomoč pri nastavitvi vaše delovne postaje si oglejte članek o dokumentaciji Joomla "Nastavitev vaše delovne postaje za razvoj Joomla" . Za Cypress so informacije na cypress.io . Vendar to na tej točki ni potrebno. Joomla nastavi vse Samo nastaviti morate svoje individualne podatke prek konfiguracijske datoteke joomla-cms/cypress.config.js.

Nastavite svoje individualne podatke. Za to lahko uporabite predlogo joomla-cms/cypress.config.dist.jskot orientacijo. V mojem primeru je ta datoteka videti takole:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  fixturesFolder: 'tests/cypress/fixtures',
  videosFolder: 'tests/cypress/output/videos',
  screenshotsFolder: 'tests/cypress/output/screenshots',
  viewportHeight: 1000,
  viewportWidth: 1200,
  e2e: {
    setupNodeEvents(on, config) {},
    baseUrl: 'http://localhost/joomla-cms',
    specPattern: [
      'tests/cypress/integration/install/*.cy.{js,jsx,ts,tsx}',
      'tests/cypress/integration/administrator/**/*.cy.{js,jsx,ts,tsx}',
      'tests/cypress/integration/module/**/*.cy.{js,jsx,ts,tsx}',
      'tests/cypress/integration/site/**/*.cy.{js,jsx,ts,tsx}'
    ],
    supportFile: 'tests/cypress/support/index.js',
    scrollBehavior: 'center',
    browser: 'firefox',
    screenshotOnRunFailure: true,
    video: false
  },
  env: {
    sitename: 'Joomla CMS Test',
    name: 'admin',
    email: Ta e-poštni naslov je zaščiten proti smetenju. Potrebujete Javascript za pogled.',
    username: 'admin',
    password: 'adminadminadmin',
    db_type: 'MySQLi',
    db_host: 'mysql',
    db_name: 'test_joomla',
    db_user: 'root',
    db_password: 'root',
    db_prefix: 'j4_',
  },
})

Konkretno sem dodal imenik tests/cypress/integration/module/**/*.cy.{js,jsx,ts,tsx}v specPattern Array, ker želim tja kasneje shraniti test za module. Nato sem spremenil uporabniško ime in gesla, ker želim tudi ročno preizkusiti namestitev in si bolje zapomniti samododeljena. Uporabljam Docker kontejner kot baza podatkov. Zato sem spremenil strežnik baze podatkov in dostopne podatke. In končno sem moral nastaviti korenski URL http://localhost/joomla-cmssvoje namestitve Joomla.

Uporabi Cypress

Preko spletnega brskalnika

Pokličite npm run cypress:openprek CLI v vašem korenskem imeniku Joomla. Kmalu kasneje se bo odprla aplikacija Cypress. Pred tem smo ustvarili datoteko. joomla-cms/cypress.config.dist.jsDa je to zaznano, je razvidno iz dejstva, da je testiranje E2E določeno kot konfigurirano.

Aplikacija Cypress se odpre po klicu 96;npm run cypress:open96;.

Tukaj lahko izberete, ali želite zagnati teste E2E in kateri brskalnik želite uporabiti. Za primer sem izbral možnost "Začni testiranje v Firefoxu".

E2E testi v aplikaciji Cypress: izberite brskalnik, ki ga želite uporabiti.

Vsi razpoložljivi testni paketi bodo navedeni in lahko kliknete tistega, ki ga želite zagnati. Ko izberete testni paket, se bodo testi izvajali in si lahko ogledate izvajanje testov v realnem času v brskalniku.

Testna zbirka Joomla v Firefoxu prek aplikacije Cypress.

Med izvajanjem testov lahko na eni strani vidite izvedeni skript, na desni pa rezultat v brskalniku. To niso le posnetki zaslona, ​​ampak pravi posnetki brskalnika v tistem trenutku, tako da lahko vidite dejansko kodo HTML Možni so tudi posnetki zaslona in celo videoposnetki testov.

Test namestitve Joomla v teku.

Preizkusite. Če uporabljate as, db_host: 'localhost',lahko preizkusite namestitev in tako pravilno konfigurirate Joomlo za delo v naslednjem delu tega besedila.

Če vi, tako kot jaz, uporabljate zunanji vir (ne lcoalhost; jaz uporabljam vsebnik docker) kot db_host, preizkus za to vrsto namestitve še ni pripravljen. V tem primeru obstaja vprašanje glede varnosti v namestitveni rutini, ki je še ni upoštevano v testih. V tem primeru Joomla namestite ročno s podatki, vnesenimi v datoteko joomla-cms/cypress.config.js. Naslednji testi bodo uporabili nastavitve iz te konfiguracijske datoteke, na primer za prijavo v skrbniško področje Joomla. Tako razvijalec testa ni treba skrbeti za vnos podatkov za prijavo.Ujemajoči se uporabnik in geslo se vedno samodejno uporabita iz konfiguracijske datoteke.

Brez glave

Privzeto cypress runzažene vse teste brez glave/joomla-cms/tests/cypress/output/screenshots . Naslednji ukaz izvede vse že kodirane teste in v primeru napake shrani posnetke zaslona v imenik . Izhodni imenik je bil nastavljen v cypress.config.jsdatoteki.

$ npm run cypress:run

Drugi ukazi CLI

Obstajajo še drugi koristni ukazi, ki niso implementirani kot skripti v package.jsonprojektu Joomla. Izvajam jih prek npx [docs.npmjs.com/commands/npx].

čempres preveriti

Ukaz cypress verifypreveri, ali je Cypress pravilno nameščen in ga je mogoče zagnati.

$ npx cypress verify

✔  Verified Cypress! /.../.cache/Cypress/12.8.1/Cypress
informacije o čempresu

Ukaz cypress infoizpiše informacije o Cypressu in trenutnem okolju.

$ npx cypress info
Displaying Cypress info...

Detected 2 browsers installed:

1. Chromium
  - Name: chromium
  - Channel: stable
  - Version: 113.0.5672.126
  - Executable: chromium
  - Profile: /.../snap/chromium/current

2. Firefox
  - Name: firefox
  - Channel: stable
  - Version: 113.0.1
  - Executable: firefox
  - Profile: /.../snap/firefox/current/Cypress/firefox-stable

Note: to run these browsers, pass : to the '--browser' field

Examples:
- cypress run --browser chromium
- cypress run --browser firefox

Learn More: https://on.cypress.io/launching-browsers

Proxy Settings: none detected
Environment Variables: none detected

Application Data: /.../.config/cypress/cy/development
Browser Profiles: /.../.config/cypress/cy/development/browsers
Binary Caches: /.../.cache/Cypress

Cypress Version: 12.8.1 (stable)
System Platform: linux (Ubuntu - 22.04)
System Memory: 4.08 GB free 788 MB
različica ciprese

Ukaz cypress versionnatisne nameščeno binarno različico Cypress, različico paketa Cypress, različico Electron, uporabljeno za ustvarjanje Cypressa, in različico združenega vozlišča.

$ npx cypress version
Cypress package version: 12.8.1
Cypress binary version: 12.8.1
Electron version: 21.0.0
Bundled Node version: 16.16.0

Dokumentacija podjetja Cypress ponuja podrobnejše informacije.

Pisanje prvega lastnega testa

Če je do zdaj vse delovalo, lahko začnemo ustvarjati lastne teste.

Pridobite pregled

Učenje iz že razvitih testov

V razvojni različici Joomla CMS so že Cypress testi, ki so v mapi /tests/System/integration.Tisti, ki se radi učite na zgledih, boste tukaj našli primeren uvod.

Uvoz kode za ponavljajoče se naloge

Razvijalci Joomla delajo na projektu NodeJs joomla-cypress , ki zagotavlja preskusno kodo za običajne testne primere. Ti se uvozijo med namestitvijo razvijalske različice CMS z uporabo npm installprek

  • package.jsonin prek
  • Podporna datoteka /tests/System/support/index.jsPodporna datoteka je definirana v konfiguraciji cypress.config.js.
// package.json
{
  "name": "joomla",
  "version": "5.0.0",
  "description": "Joomla CMS",
  "license": "GPL-2.0-or-later",
  "repository": {
    "type": "git",
    "url": "https://github.com/joomla/joomla-cms.git"
  },
...
  "devDependencies": {
    ...
    "joomla-cypress": "^0.0.16",
    ...
  }
}

Primer je klik na gumb v orodni vrstici. Na primer, Cypress.Commands.add('clickToolbarButton', clickToolbarButton)povzroči, da je ukaz clickToolbarButton()na voljo v preizkusih po meri in s cy.clickToolbarButton('new')klikom na gumb Newje simuliran. Koda, potrebna za to, je prikazana v spodnjem izrezku kode.

// node_modules/joomla-cypress/src/common.js
...
const clickToolbarButton = (button, subselector = null) => {
  cy.log('**Click on a toolbar button**')
  cy.log('Button: ' + button)
  cy.log('Subselector: ' + subselector)

  switch (button.toLowerCase())
  {
    case "new":
      cy.get("#toolbar-new").click()
      break
    case "publish":
      cy.get("#status-group-children-publish").click()
      break
    case "unpublish":
      cy.get("#status-group-children-unpublish").click()
      break
    case "archive":
      cy.get("#status-group-children-archive").click();
      break
    case "check-in":
      cy.get("#status-group-children-checkin").click()
      break
    case "batch":
      cy.get("#status-group-children-batch").click()
      break
    case "rebuild":
      cy.get('#toolbar-refresh button').click()
      break
    case "trash":
      cy.get("#status-group-children-trash").click()
      break
    case "save":
      cy.get("#toolbar-apply").click()
      break
    case "save & close":
      cy.get(".button-save").contains('Save & Close').click()
      break
    case "save & new":
      cy.get("#save-group-children-save-new").click()
      break
    case "cancel":
      cy.get("#toolbar-cancel").click()
      break
    case "options":
      cy.get("#toolbar-options").click()
      break
    case "empty trash":
    case "delete":
      cy.get("#toolbar-delete").click()
      break
    case "feature":
      cy.get("#status-group-children-featured").click()
      break
    case "unfeature":
      cy.get("#status-group-children-unfeatured").click()
      break
    case "action":
      cy.get("#toolbar-status-group").click()
      break
    case "transition":
      cy.get(".button-transition.transition-" + subselector).click()
      break
  }

  cy.log('--Click on a toolbar button--')
}

Cypress.Commands.add('clickToolbarButton', clickToolbarButton)
...

Naslednja koda prikazuje še en primer, prijavo v skrbniško področje.

// /node_modules/joomla-cypress/src/user.js
...
const doAdministratorLogin = (user, password, useSnapshot = true) => {
  cy.log('**Do administrator login**')
  cy.log('User: ' + user)
  cy.log('Password: ' + password)

  cy.visit('administrator/index.php')
  cy.get('#mod-login-username').type(user)
  cy.get('#mod-login-password').type(password)
  cy.get('#btn-login-submit').click()
  cy.get('h1.page-title').should('contain', 'Home Dashboard')

  cy.log('--Do administrator login--')
}

Cypress.Commands.add('doAdministratorLogin', doAdministratorLogin)

...
Skupna opravila v individualnem okolju

V imeniku /tests/System/supportboste našli običajna opravila v posameznem okolju. Da jih je mogoče enostavno ponovno uporabiti, so uvožena preko podporne datoteke. /tests/System/support/index.jsPrimer pogosto ponavljajočega se opravila je prijava v skrbniško področje, ki je obdelana v datoteki /tests/System/support/commands.jsz uporabo funkcije doAdministratorLogin.

Naslednja koda prikazuje tudi, kako se informacije iz cypress.config.jskonfiguracije uporabljajo v testih. Cypress.env('username')je dodeljena vrednost lastnosti usernameznotraj skupine env.

Tukaj lahko tudi vidimo, kako prepisati ukaze. Cypress.Commands.overwrite('doAdministratorLogin' ...),prepiše kodo, ki smo jo pravkar videli v paketu joomla-cypress. Prednost je, da se uporabnik in geslo samodejno uporabita iz posamezne konfiguracije.

// /tests/System/support/commands.js
...
Cypress.Commands.overwrite('doAdministratorLogin', (originalFn, username, password, useSnapshot = true) => {
  // Ensure there are valid credentials
  const user = username ?? Cypress.env('username');
  const pw = password ?? Cypress.env('password');

  // Do normal login when no snapshot should be used
  if (!useSnapshot) {
    // Clear the session data
    Cypress.session.clearAllSavedSessions();

    // Call the normal function
    return originalFn(user, pw);
  }

  // Do login through the session
  return cy.session([user, pw, 'back'], () => originalFn(user, pw), { cacheAcrossSpecs: true });
});
...

Namestite lastno razširitev Joomla

Da bi videli, kako preizkusite svojo lastno kodo, bomo namestili preprost primer komponente prek ozadja Joomla. Datoteko za namestitev lahko prenesete s spletnega mesta Codeberg .

Namestite lastno Joomla razširitev.

Po namestitvi lahko najdete povezavo do pogleda komponente Foo v levi stranski vrstici zaledja Joomla.

Pogled vzorčne komponente v ozadju Joomla.

Zdaj imamo nastavljeno testno okolje in kodo za testiranje.

Prvi lastni test

Kljuke

Pri testiranju zaledja boste opazili, da morate vsak test začeti s prijavo. To odvečno kodo lahko preprečimo z uporabo funkcije. beforeEach()Ta tako imenovana kljuka izvede kodo, ki jo vnesemo pred vsakim testom. Od tod tudi ime beforeEach().

Cypress ponuja več vrst kavljev , vključno befores afterkavlji, ki se izvajajo pred ali po testih v testni skupini, in beforeEachkavlji afterEach, ki se izvajajo pred ali po vsakem posameznem testu v skupini. Kavlji se lahko definirajo globalno ali znotraj določenega describedbloka. primer kode v datoteki tests/System/integration/administrator/components/com_foos/FoosList.cy.jspovzroči izvedbo prijave v ozadju pred vsakim preizkusom znotraj describedbloka test com_foos features.

Zdaj začnemo s praktičnim delom in ustvarimo datoteko tests/System/integration/administrator/components/com_foos/FoosList.cy.jsz naslednjim odrezkom kode, preden napišemo prvi produktivni test. Naš prvi primer bi nas moral uspešno prijaviti v zaledje pred kakršnim koli testom! To bomo preizkusili po ustvarjanju prvega testa.

// tests/System/integration/administrator/components/com_foos/FoosList.cy.js

describe('Test com_foos features', () => {
  beforeEach(() => {
    cy.doAdministratorLogin()
  })

})

Opomba: Kavlji, ki so implementirani znotraj datoteke /tests/System/support/index.js, veljajo za vsako testno datoteko v testni obleki.

Uspešen test

Komponenta, ki smo jo namestili za testiranje Astrid, vsebuje tri elemente Ninain ElmarNajprej preizkusimo, ali so bili ti elementi uspešno ustvarjeni.

// tests/System/integration/administrator/components/com_foos/FoosList.cy.js

describe('Test com_foos features', () => {
  beforeEach(() => {
    cy.doAdministratorLogin()
  })

  it('list view shows items', function () {
    cy.visit('administrator/index.php?option=com_foos')

    cy.get('main').should('contain.text', 'Astrid')
    cy.get('main').should('contain.text', 'Nina')
    cy.get('main').should('contain.text', 'Elmar')

    cy.checkForPhpNoticesOrWarnings()
  })
})

Opomba: funkcija, checkForPhpNoticesOrWarnings()ki jo najdete v datoteki /node_modules/joomla-cypress/src/support.js.

Element DOM dobimo mainpreko ukaza Cypress get

Svoj pravkar ustvarjeni test bi morali najti FooList.cy.jsna seznamu razpoložljivih testov v levi stranski vrstici. Če temu ni tako, zaprite brskalnik in zaženite npm run cypress:openznova.

Joomla zaženi test za lastno razširitev.

Kliknite na ime testa, da ga zaženete. Moral bi se uspešno končati in videli boste zelena sporočila.

Pogled po uspešno izvedenem testu.

Neuspešen test

Dodajte vrstico cy.get('main').should('contain.text', 'Sami')v testno datoteko, tako da izvajanje ne uspe. Ni elementa s tem imenom. Po shranjevanju testne datoteke Cypress opazi spremembo. Po vsaki spremembi Cypress samodejno znova zažene vse teste v testni datoteki.

// tests/System/integration/administrator/components/com_foos/FoosList.cy.js
describe('Test com_foos features', () => {
  beforeEach(() => {
    cy.doAdministratorLogin()
  })

  it('list view shows items', function () {
    cy.visit('administrator/index.php?option=com_foos')

    cy.get('main').should('contain.text', 'Astrid')
    cy.get('main').should('contain.text', 'Nina')
    cy.get('main').should('contain.text', 'Elmar')
    cy.get('main').should('contain.text', 'Sami')

    cy.checkForPhpNoticesOrWarnings()
  })
})

Kot je bilo pričakovano, test ne uspe. Obstajajo rdeča sporočila. Kodo vsakega testnega koraka lahko vidite v levi stranski vrstici. Tako je mogoče najti razlog za napako. Za vsak korak obstaja posnetek dokumenta HTML, tako da lahko kadar koli preverite oznake. To je koristno, zlasti med razvojem.

Pogled po neuspelem testu.

Izvedite samo en test v datoteki

Naša demo razširitev vsebuje več kot eno postavitev. Dodajte test za preizkušanje postavitve praznega stanja. Ker imamo zdaj v tej datoteki dva testa, bo Cypress vedno zagnal oba testa vsakič, ko shranimo datoteko. Uporabimo lahko tako, da samo en .only()test se izvaja:

// tests/System/integration/administrator/components/com_foos/FoosList.cy.js

describe('Test com_foos features', () => {
    beforeEach(() => {
        cy.doAdministratorLogin()
    })

    it('list view shows items', function () {
        cy.visit('administrator/index.php?option=com_foos')

        cy.get('main').should('contain.text', 'Astrid')
        cy.get('main').should('contain.text', 'Nina')
        cy.get('main').should('contain.text', 'Elmar')

        cy.checkForPhpNoticesOrWarnings()
    })

    it.only('emptystate layout', function () {
        cy.visit('administrator/index.php?option=com_foos&view=foos&layout=emptystate')
        cy.get('main').should('contain.text', 'No Foo have been created yet.')
    })
})

Med razvojem je to zelo priročno.

Posebni testni atributi

Zdaj želimo preizkusiti sprednji del naše komponente. To naredimo v ločeni datoteki /tests/System/integration/site/components/com_foos/FooItem.cy.js.

Večino časa uporabljamo razred CSS za pridobivanje elementov v testih Joomla. Čeprav je to popolnoma veljavno in bo delovalo, dejansko ni priporočljivo. Zakaj ne? Ko uporabljate razrede ali ID-je CSS, svoje teste povežete s stvarmi, ki se bodo sčasoma najverjetneje spremenili. Razredi in ID-ji so za načrtovanje, postavitev in včasih preko JavaScripta za nadzor, ki se lahko zlahka spremeni. Če nekdo spremeni ime razreda ali ID, vaši testi ne bodo več delovali. Da bodo vaši testi manj krhki in bolj pripravljen na prihodnost, Cypress priporoča ustvarjanje posebnih podatkovnih atributov za vaše elemente posebej za namene testiranja.

Za elemente bom uporabil data-testatribut. Najprej dodam atribut data-test="foo-main"v produkcijsko kodo.

// /components/com_foos/tmpl/foo/default.php

\defined('_JEXEC') or die;
?>
<div data-test="foo-main">
Hello Foos
</div>

Nato preizkusim produkcijsko kodo z iskanjem atributa [data-test="foo-main"].

// tests/System/integration/site/components/com_foos/FooItem.cy.js
describe('Test com_foo frontend', () => {
  it('Show frondend via query in url', function () {
    cy.visit('index.php?option=com_foos&view=foo')

    cy.get('[data-test="foo-main"]').should('contain.text', 'Hello Foos')

    cy.checkForPhpNoticesOrWarnings()
  })
})
Preizkušanje menijskega elementa in nekaj misli o dogodkih, čakanju in najboljši praksi

Zdaj rad preizkusim ustvarjanje menijske postavke za našo komponento. To počnem v ločeni datoteki /tests/System/integration/administrator/components/com_foos/MenuItem.cy.js. Ta koda je zapletena in prikazuje veliko posebnih funkcij.

Najprej sem definiral konstanto, v kateri nastavim vse relevantne lastnosti menijske postavke. To ima prednost, da moram v primeru sprememb relevantne lastnosti prilagoditi le na enem mestu:

const testMenuItem = {
  'title': 'Test MenuItem',
  'menuitemtype_title': 'COM_FOOS',
  'menuitemtype_entry': 'COM_FOOS_FOO_VIEW_DEFAULT_TITLE'
}

Nato vidite celotno kodo datoteke MenuItem.cy.js:

// tests/System/integration/administrator/components/com_foos/MenuItem.cy.js

describe('Test menu item', () => {
  beforeEach(() => {
    cy.doAdministratorLogin(Cypress.env('username'), Cypress.env('password'))
  })

  it('creates a new menu item', function () {
    const testMenuItem = {
      'title': 'Test MenuItem',
      'menuitemtype_title': 'COM_FOOS',
      'menuitemtype_entry': 'COM_FOOS_FOO_VIEW_DEFAULT_TITLE'
    }

    cy.visit('administrator/index.php?option=com_menus&view=item&client_id=0&menutype=mainmenu&layout=edit')
    cy.checkForPhpNoticesOrWarnings()
    cy.get('h1.page-title').should('contain', 'Menus: New Item')

    cy.get('#jform_title').clear().type(testMenuItem.title)

    cy.contains('Select').click()
    cy.get('.iframe').iframe('#collapse1-heading').contains(testMenuItem.menuitemtype_title).click()
    cy.get('.iframe').iframe('#collapse1-heading').contains(testMenuItem.menuitemtype_entry).click()

    cy.intercept('index.php?option=com_menus&view=items&menutype=mainmenu').as('item_list')
    cy.clickToolbarButton('Save & Close')
    cy.wait('@item_list')
    cy.get('#system-message-container').contains('Menu item saved.').should('exist')

    // Frontend
    cy.visit('index.php')
    cy.get('.sidebar-right').contains(testMenuItem.title).click()
    cy.get('[data-test="foo-main"]').should('contain.text', 'Hello Foos')
    cy.checkForPhpNoticesOrWarnings()

    // Trash
    cy.visit('administrator/index.php?option=com_menus&view=items&menutype=mainmenu')
    cy.searchForItem(testMenuItem.title)
    cy.checkAllResults()
    cy.clickToolbarButton('Action')
    cy.intercept('index.php?option=com_menus&view=items&menutype=mainmenu').as('item_trash')
    cy.clickToolbarButton('trash')
    cy.wait('@item_trash')
    cy.get('#system-message-container').contains('Menu item trashed.').should('exist')

    // Delete
    cy.visit('administrator/index.php?option=com_menus&view=items&menutype=mainmenu')
    cy.setFilter('published', 'Trashed')
    cy.searchForItem(testMenuItem.title)
    cy.checkAllResults()
    cy.on("window:confirm", (s) => {
      return true;
    });
    cy.intercept('index.php?option=com_menus&view=items&menutype=mainmenu').as('item_delete')
    cy.clickToolbarButton('empty trash');
    cy.wait('@item_delete')
    cy.get('#system-message-container').contains('Menu item deleted.').should('exist')
  })
})
  • V tej kodi lahko vidite primer testiranja nečesa in nato izbrisa vsega - s čimer obnovite začetno stanje. Na ta način lahko ponavljate teste kolikorkrat želite. Brez obnovitve začetnega stanja bo drugi testni zagon neuspešen, ker Joomla ne more shraniti dveh podobnih elementov.

Opomba: test mora biti:

  • ponovljivo.
  • Konkretno to pomeni, da mora testirati omejen problem in koda za to ne sme biti preobsežna.
  • neodvisen od drugih testov.
  • In lahko vidite, kako uporabiti prestreženo pot, definirano z cy.intercept()[^docs.cypress.io/api/commands/intercept] kot vzdevek, in nato počakati na pot, definirano kot vzdevek z cy.wait().

Pri pisanju testov za takšne aplikacije pride do skušnjave, da bi uporabili naključne vrednosti, kot je na primer cy.wait(2000);v cy.waitukazu. Težava s tem pristopom je, da lahko to dobro deluje v razvoju. Vendar ni zagotovljeno, da bo vedno delovalo. Zakaj? Ker osnovni sistem je odvisen od stvari, ki jih je težko predvideti, zato je vedno bolje natančno definirati, kaj čakate.

  • Koda tudi prikazuje, kako počakati na opozorilo in ga potrditi .
cy.on("window:confirm", (s) => {
  return true;
});
  • Nenazadnje testna koda vsebuje Cypress build in in Joomla tipične funkcije, ki jih razvijalci razširitev lahko ponovno uporabijo, cy.setFilter('published', 'Trashed')ali cy.clickToolbarButton('Save & Close')so na primer funkcije, v katerih se na splošno najdejo rešitve za posamezne teste in ki jih razvijalci Joomle pogosto potrebujejo .
Mešanje asinhrone in sinhronizacijske kode

Ukazi Cypress so asinhroni, to pomeni, da ne vrnejo vrednosti, ampak generatenjo. Ko zaženemo Cypress, ukazov ne izvede takoj, ampak jih bere serijsko in postavlja v čakalno vrsto. Če v testih mešate asinhrono in sinhrono kodo, lahko dobite nepričakovane rezultate. Če zaženete naslednjo kodo, boste proti pričakovanjem prejeli napako. Zagotovo bi tudi pričakovali, da mainText = $main.text()spremeni vrednost mainText. Vendar mainText === 'Initial'je na koncu še vedno veljavna. Zakaj je tako? Cypress najprej izvede sinhrono kodo na na začetku in na koncu.Šele nato pokliče asinhroni del znotraj.To then()pomeni, da se spremenljivka mainTextinicializira in takoj zatem se preveri, če se je spremenila - kar seveda ne drži.

let mainText = 'Initial';
cy.visit('administrator/index.php?option=com_foos&view=foos&layout=emptystate')
cy.get("main").then(
  ($main) => (mainText = $main.text())
);

if (mainText === 'Initial') {
  throw new Error(`Der Text hat sich nicht geändert. Er lautet: ${mainText}`);
}

Obdelava čakalne vrste postane povsem jasna in nazorna, če opazujemo izvajanje naslednje kode v konzoli brskalnika. Besedilo 'Cypress Test' se pojavi veliko preden je prikazana vsebina elementa, čeprav so vrstice mainkode v drugačnem vrstnem redu.

cy.get('main').then(function(e){
  console.log(e.text())
})
console.log('Cypress Test.')
Škrbine in vohuni

A stubje način za simulacijo obnašanja funkcije, od katere so odvisni testi. Namesto klica dejanske funkcije škrbina nadomesti to funkcijo in vrne vnaprej določen objekt. Običajno se uporablja v testih enote, lahko pa tudi za konec - testiranje do konca.

A spyje podoben stub, vendar ni povsem enak. Ne spremeni vedenja funkcije, ampak jo pusti tako, kot je. Zajame nekaj informacij o tem, kako se funkcija kliče. Na primer, da preveri, ali je funkcija klicana s pravilnimi parametri ali za štetje, kako pogosto je funkcija klicana.

Naslednji primer prikazuje a spyin a stubv akciji. Prek const stub = cy.stub()ustvarimo stubelement in v naslednjem koraku določimo, ki se falsevrne za prvi klic in trueza drugega. Z uporabo cy.on('window:confirm', stub)naredimo, da stubse uporablja za window:confirm'. V naslednjem koraku ustvarimo z cy.spy(win, 'confirm').as('winConfirmSpy')elementom Spy, ki opazuje klic 'window:confirm'. Zdaj testiramo, da je pri prvem klicu izbris kategorije zavrnjen in pri drugem klicu potrjen. Pri tem zagotavlja, stubda lahko zagotovo pričakujemo, kakšne bodo vrnjene vrednosti dostavljeno. 'window:confirm'je enkapsulirano. @winConfirmSpypomaga zagotoviti, da je bila funkcija dejansko klicana - in kako pogosto je bila klicana.

// tests/System/integration/administrator/components/com_foos/FoosList.cy.js
...
const stub = cy.stub()

stub.onFirstCall().returns(false)
stub.onSecondCall().returns(true)

cy.on('window:confirm', stub)

cy.window().then(win => {
  cy.spy(win, 'confirm').as('winConfirmSpy')
})

cy.intercept('index.php?option=com_categories&view=categories&extension=com_foos').as('cat_delete')
cy.clickToolbarButton('empty trash');

cy.get('@winConfirmSpy').should('be.calledOnce')
cy.get('main').should('contain.text', testFoo.category)


cy.clickToolbarButton('empty trash');
cy.wait('@cat_delete')

cy.get('@winConfirmSpy').should('be.calledTwice')

cy.get('#system-message-container').contains('Category deleted.').should('exist')
...

Če gre le za nastavitev fiksne vrednosti za 'window:confirm'klic, bo naslednja koda opravila delo.

cy.on("window:confirm", (s) => {
  return true;
});

sklep

V tem članku ste videli osnovno teorijo in praktične značilnosti testiranja E2E s Cypressom. Z namestitvijo Joomla sem pokazal, kako napisati različne teste, da zagotovim, da komponenta Joomla na spletnem mestu deluje po pričakovanjih. Pokazal sem tudi, kako prilagoditi Cypress Test Runner v datoteki cypress.json in kako uporabljati prilagojene ukaze Cypress. To je bilo narejeno z uporabo preprostih primerov.

Upam, da ste uživali v ogledu Cypressa z uporabo Joomle kot primera in da ste lahko zase odnesli veliko znanja in navdiha.

An online collaborative community manual for Joomla! users, developers or anyone interested in learning more about Joomla! Currently, we have more than 9,000 articles written, maintained, and translated by our Joomla! community members. 

Upoštevajte, da to spletno mesto uporablja samodejni prevajalski sistem za pomoč pri prevajanju za različne jezike. Opravičujemo se za morebitne napake ali napake, ki so lahko prikazane v različnih besedilih.