Bine ai revenit! Dacă ați pierdut până acum prima parte a călătoriei noastre, atunci vă recomandăm să vă întoarceți mai întâi.
Până acum, am aplicat un proces de dezvoltare bazat pe testare pentru a construi aplicația noastră, alături de utilizarea cadrului popular de testare RSpec. De aici, vom investiga câteva alte caracteristici RSpec, precum și de a examina utilizarea gemului Pry pentru a vă ajuta să depanați și să scrieți codul.
Să facem câteva momente pentru a examina câteva alte caracteristici RSpec pe care nu le-am avut nevoie în această aplicație simplă, dar ați putea găsi util să lucrați la propriul proiect.
Imaginați-vă că ați scris un test, dar sunteți întrerupt, sau trebuie să plecați pentru o întâlnire și nu ați finalizat încă codul necesar pentru a trece testul.
Ați putea să ștergeți testul și să îl re-scrieți mai târziu, atunci când vă puteți întoarce la munca dvs. Sau, alternativ, ai putea să comentezi codul, dar e destul de urât și, cu siguranță, nu este bun atunci când folosești un sistem de control al versiunii.
Cel mai bun lucru pe care trebuie să-l facem în această situație este acela de a defini testul nostru ca fiind "în așteptare" astfel încât ori de câte ori se efectuează testele, cadrul de testare va ignora testul. Pentru a face acest lucru trebuie să utilizați in asteptarea
cuvinte cheie:
descrieți "o anumită metodă", faceți-o "ar trebui să faceți ceva" în așteptarea sfârșitului final
Toate cadrele de testare bune vă permit să executați codul înainte și după fiecare test efectuat. RSPE nu este diferit.
Ne oferă inainte de
și după
metode care ne permit să stabilim o stare specifică pentru ca testul să funcționeze și apoi să curețe acea stare după ce testul a trecut (aceasta este situația în care statul nu scapă și nu influențează rezultatul testelor ulterioare).
descrieți "o anumită metodă" înainte de (: fiecare) face # un sfârșit de cod setat după (: fiecare) face # un sfârșit de cod în final "ar trebui să facă ceva"
Am văzut-o deja descrie
bloc; dar există un alt bloc care este denumit funcțional echivalent context
. Puteți să-l folosiți oriunde ați folosi descrie
.
Diferența dintre ele este subtilă, dar importantă: context
ne permite să definim o stare pentru testul nostru. Nu în mod explicit (nu stabilim de fapt statul prin definirea unui context
bloc - în schimb este în scop de citire, astfel încât intenția următorului cod este mai clară).
Iată un exemplu:
descrieți "Unele metodă" face context "bloc furnizat" face "randamente pentru a bloca" face în așteptare sfârșitul sfârșitul context "nici un bloc cu condiția" a face "apeluri o metodă de rezervă"
Putem folosi ciot
metodă de a crea o versiune falsă a unui obiect existent și de ao returna o valoare prestabilită.
Acest lucru este util pentru a împiedica testele noastre să atingă API-urile de serviciu live și să ghideze testele noastre, oferind rezultate previzibile din anumite apeluri.
Imaginați-vă că avem o clasă chemată Persoană
și că această clasă are a vorbi
metodă. Vrem să testăm că această metodă funcționează așa cum ne așteptăm. Pentru a face acest lucru vom stub vorbi
folosind următorul cod:
descrie persoana care o face "vorbi ()" do bob = stub () bob.stub (: vorbesc) .and_return ('hello') Person.any_instance.stub (: initialize) .and_return (bob) example.speak). la eq ('hello') end end
În acest exemplu, spunem că "orice instanță" a Persoană
clasa ar trebui să aibă inițializa
metoda stubbed astfel încât returnează obiectul bob
.
Veți observa asta bob
este el însuși un stub care este set-up, astfel încât orice cod de timp încearcă să execute vorbi
metoda va reveni "hello".
Apoi continuăm să creăm un nou Persoană
instanță și să treacă apelul instance.speak
în RSpec aştepta
sintaxă.
Spunem RSpec că ne așteptăm ca apelul să ducă la String "hello".
În exemplele anterioare am folosit funcția RSpec and_return
pentru a indica ce ar trebui să ne întoarcă stubul nostru atunci când este chemat.
Putem indica o valoare de retur diferită de fiecare dată când se cheamă stubul prin specificarea mai multor argumente către and_return
metodă:
(1, 2, 3) așteptați (obj.foo ()) la eq (1) așteptați (obj.foo ()) la eq (2) așteptați (obj.foo ()) la eq (3)
Mocks sunt similare cu Stubs, prin faptul că suntem crearea de variante false ale obiectelor noastre, dar în loc de a reveni o valoare predefinită suntem mai precis călăuzește rutele obiectele noastre trebuie sa pentru ca testul să fie valabil.
Pentru a face acest lucru vom folosi a-și bate joc
metodă:
descrie Obj face "test" () "do bob = mock () bob.should_receive (: testing) .with ('content') Obj.any_instance.stub (: initialize) .and_return (bob) instance = Obj.new instance. testarea ("o anumită valoare")
În exemplul de mai sus, creăm un nou Obiect
și apoi să-i numiți testarea
metodă.
În spatele scenei din acel cod ne așteptăm testarea
metoda care trebuie apelată cu valoarea 'conţinut'
. Dacă nu este numit cu acea valoare (care în exemplul de mai sus nu este) atunci știm că o bucată din codul nostru nu a funcționat corect.
subiect
cuvântul cheie poate fi folosit în câteva moduri diferite. Toate acestea sunt concepute pentru a reduce duplicarea codului.
Puteți folosi implicit (observați-ne aceasta
blocul nu se referă subiect
deloc):
descrie matricea descriu "cu 3 elemente" face obiectul [1,2,3] it should_not be_empty end end
Puteți să o utilizați în mod explicit (observați-ne aceasta
bloc se referă la subiect
direct):
descrie MyClass descriu "initializare" face obiectul MyClass it "creează o nouă instanță" do instance = subject.new așteptați (instanță) .to be_a (MyClass) end end end
Mai degrabă decât să raportați constant un subiect în codul dvs. și să transmiteți diferite valori pentru instanțiere, de exemplu:
descrie "Foo" face contextul "A" face "Bar" do baz = Baz.new ('a') asteapta (baz.type) do baz = Baz.new ('b') asteapta (baz.type). la eq ('b') contextul final "C" face "Bar" .type) la eq ('c') sfârșitul capătului final
Puteți folosi în schimb subiect
impreuna cu lăsa
pentru a reduce duplicarea:
descrie "Persoana" face obiectul Person.new (name) # Persoana are un context de metoda get_name "Bob" nu lasa (: name) 'Bob' "Joe" nu permite (: name) 'Joe' lui (: get_name) should == 'Joe' == 'Smith' sfârșitul final
Există multe alte caracteristici disponibile pentru RSpec, dar ne-am uitat la cele mai importante pe care le veți găsi folosind multe atunci când scrieți teste folosind RSpec.
Puteți configura RSpec pentru a executa testele dvs. într-o ordine aleatorie. Acest lucru vă permite să vă asigurați că niciunul dintre testele dvs. nu are încredere sau dependență de celelalte teste din jurul acestuia.
RSpec.configure do | config | config.order = sfârșitul "aleatoriu"
Puteți seta acest lucru prin comandă utilizând tasta --Ordin
pavilion / opțiune. De exemplu: rspec - rangul întâmplător
.
Când utilizați --ordine aleatoare
opțiunea RSpec va afișa numărul aleatoriu pe care la folosit pentru a însemna algoritmul. Poți folosi din nou această valoare "semințe" atunci când crezi că ai descoperit o problemă de dependență în cadrul testelor tale. Odată ce ați stabilit ceea ce credeți că este problema, puteți trece valoarea seminței în RSpec (de exemplu, dacă semințele au fost 1234
apoi executați --ordine aleatoare: 1234
) și va folosi aceleași semințe randomizate pentru a vedea dacă poate replica eroarea de dependență originală.
Ați văzut că am adăugat un set specific de proiect de obiecte de configurare în cadrul nostru Rakefile
. Dar puteți seta opțiunile de configurare la nivel global prin adăugarea lor la a .rspec
fișier în directorul de acasă.
De exemplu, înăuntru .rspec
:
--color - format imbricat
Acum suntem gata să începem să ne uităm la modul în care putem depana aplicația noastră și codul nostru de testare folosind gemul Pry.
Este important să înțelegeți că, deși Pry este foarte bun pentru depanarea codului dvs., acesta este de fapt un instrument îmbunătățit Ruby REPL (înlocuit IRB
) și nu în mod strict de depanare; astfel încât, de exemplu, nu există funcții încorporate, cum ar fi: pas în, pasul peste sau ieșirea etc, pe care le-ați găsi de obicei într-un instrument proiectat pentru depanare.
Dar, ca instrument de depanare, Pry este foarte concentrat și slab.
Vom reveni la depanare într-un moment, dar să analizăm mai întâi modul în care vom folosi inițial Pry.
În scopul de a demonstra Pry Voi adăuga mai mult cod la exemplul meu cerere (acest cod suplimentar nu efectul nostru de testare în nici un fel)
clasa RSpecGreeter attr_accessor: test @@ class_property = "Sunt o proprietate a clasei" def greet binding.pry @instance_property = "Sunt o proprietate de instanță" pubs privs "Hello RSpec!" end def pubs test_var = "Sunt o variabilă de testare" test_var sfârșitul privat def privs pune "eu sunt privat" sfârșitul sfârșitul
Veți observa că am adăugat câteva metode suplimentare, proprietăți de instanță și clase. Facem, de asemenea, apeluri la două dintre noile metode pe care le-am adăugat din cadrul nostru întâmpina
metodă.
În cele din urmă, veți observa utilizarea binding.pry
.
binding.pry
O pauză este un loc în codul tău unde execuția se va opri.
Puteți avea mai multe puncte de pauză setate în codul dvs. și le puteți crea utilizând binding.pry
.
Când executați codul, veți observa că terminalul se va opri și vă va plasa în codul aplicației la locul exact la care a fost plasat legătura..
Mai jos este un exemplu de cum ar putea arata ...
8: def greet => 9: link.pry 10: pubs 11: privs 12: "Hello RSpec!" 13: sfârșit
Din acest punct, Pry are acces la domeniul de aplicare local, astfel încât să puteți folosi Pry așa cum ați face IRB
și începeți să introduceți, de exemplu, variabilele pentru a vedea ce valori dețin.
Puteți rula Ieșire
pentru a ieși din programul Pry și pentru ca codul să continue să se execute.
unde sunt
Când folosiți o mulțime de binding.pry
punctele de pauză poate fi dificil de înțeles în cazul în care sunteți în aplicație.
Pentru a obține un context mai bun în care vă aflați în orice moment, puteți utiliza funcția unde sunt
comanda.
Când alergi singur, vei vedea ceva similar cu cel folosit binding.pry
(veți vedea linia pe care a fost setat punctul de rupere și câteva linii deasupra și dedesubt). Diferența este dacă dai un argument numeric suplimentar undeami 5
veți vedea cinci linii suplimentare de mai sus în cazul în care binding.pry
a fost așezat. Ați putea cere să vedeți, de exemplu, 100 de linii în jurul punctului curent de rupere.
Această comandă vă poate ajuta să vă orientați în fișierul curent.
WTF
WTF
comanda înseamnă "ceea ce f ***" și oferă o urmă completă pentru cea mai recentă excepție care a fost aruncată. Vă poate ajuta să înțelegeți pașii care au condus la eroarea care a avut loc.
ls
ls
comanda afișează ce metode și proprietăți sunt disponibile pentru Pry.
Când se execută, vă va arăta ceva de genul ...
RSpecGreeter # metode: salut pubs test test = variabile de clasă: @@ class_property localnici: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_
În exemplul de mai sus, putem vedea că avem patru metode publice (rețineți că am actualizat codul nostru pentru a include câteva metode suplimentare și apoi Test
și încercare =
au fost create folosind Ruby's attr_accessor
mâna scurtă).
De asemenea, afișează alte variabile de clasă și locale pe care le poate accesa Pry.
Un alt lucru util pe care îl puteți face este să grepați (căutați) rezultatele numai pentru ceea ce vă interesează. Veți avea nevoie de o înțelegere a Expresiilor regulate, dar poate fi o tehnică la îndemână. Iată un exemplu ...
ls -p -G ^ p => RSpecGreeter # metode: privs
În exemplul de mai sus, folosim -p
și -G
opțiuni / steaguri care îi spun lui Pry că dorim doar să vedem metode publice și private și folosim regex-ul ^ p
(ceea ce înseamnă că se potrivește cu orice începând cu p
) ca model de căutare pentru a filtra rezultatele.
Alergare ls - ajutor
va afișa, de asemenea, toate opțiunile disponibile.
CD
Puteți schimba domeniul de aplicare actual utilizând funcția CD
comanda.
În exemplul nostru, dacă alergăm cd ... / pub-uri
ne va duce la rezultatul apelului metodei respective.
Dacă fugim acum unde sunt
veți vedea că va fi afișat În interiorul "Sunt o variabilă de test"
.
Dacă fugim de sine
atunci veți vedea că ajungem "Sunt o variabilă de test"
întors.
Dacă fugim self.class
vom vedea Şir
întors.
Puteți să vă deplasați în sus cu ajutorul lanțului de acoperire CD…
sau puteți să vă întoarceți la cel mai înalt nivel al domeniului cd /
.
Notă: am putea adăuga un altul binding.pry
în interiorul pub-uri
și apoi domeniul nostru de aplicare ar fi în interiorul acestei metode, mai degrabă decât rezultatul metodei.
cuiburi
Luați în considerare exemplul anterior de rulare cd pub-uri
. Dacă executăm cuiburi
comanda vom obține un aspect de nivel superior asupra numărului de contexte / niveluri pe care Pry le are în prezent:
Nesting status: - 0. # (nivel superior) 1. "Sunt o variabilă de test"
De acolo putem fugi Ieșire
pentru a vă întoarce la contextul anterior (de exemplu, în interiorul întâmpina
metodă)
Alergare Ieșire
din nou, vom însemna că închidem ultimul context pe care îl are Pry și astfel Pry se termină și codul nostru continuă să ruleze.
găsi-metoda
Dacă nu sunteți sigur unde să găsiți o metodă particulară, atunci puteți folosi găsi-metoda
comanda pentru a vă arăta toate fișierele din baza dvs. de cod care au o metodă care se potrivește cu ceea ce căutați:
find-method priv => kernel Kernel # private_methods Modulul modulului # private_instance_methods Modulul # private_constant Modulul # private_method_defined? Modulul # private_class_method Modul # privat RSpecGreeter RSpecGreeter # privs
De asemenea, puteți utiliza funcția -c
opțiune / steag pentru a căuta în schimb conținutul fișierelor:
metode de căutare -c greet => RSpecGreeter RSpecGreeter: def greet RSpecGreeter # privs: salut
Următor →
, Etapa
, continua
Deși tehnicile de mai sus sunt utile, nu este într-adevăr "depanare" în același sens cu cel la care ești probabil folosit.
Pentru cei mai mulți dezvoltatori, editorul sau browserul lor le va pune la dispoziție un instrument de depanare încorporat, care le va permite să parcurgă linia de cod prin linie și să urmeze traseul pe care îl are codul până la finalizare.
Deoarece Pry este dezvoltat pentru a fi folosit ca un REPL care nu înseamnă că nu este util pentru depanare.
O soluție naivă ar fi stabilirea mai multor binding.pry
prin intermediul unei metode și a unei utilizări ctrl-d pentru a vă deplasa prin fiecare set de puncte. Dar asta nu este destul de bun.
Pentru depanarea pas cu pas puteți încărca pr ...
sursă "https://rubygems.org" gem 'rspec' grup: development do gem 'paza' gem 'guard-rspec' gem 'pry' bijuterie "sfârșitul pry-nav"
Această bijuterie extinde Pry astfel încât să înțeleagă următoarele comenzi:
Următor →
(treceți la linia următoare)Etapa
(treceți la linia următoare și dacă este o metodă, apoi treceți la metoda respectivă)Continua
(Ignorați orice alte pauze în acest fișier)Ca un bonus suplimentar, să integrăm testele noastre cu serviciul online CI (continuă integrare) Travis-CI.
Principiul CI este de a comite / împinge devreme și de multe ori pentru a evita conflictele dintre codul dvs. și ramura principală. Când faceți acest lucru (în acest caz, ne angajăm la GitHub), atunci aceasta ar trebui să pornească o "construire" pe serverul dvs. CI care execută testele relevante pentru a se asigura că toate funcționează așa cum ar trebui să fie.
Acum, cu TDD ca metodă de dezvoltare primară, este mai puțin probabil să faceți bug-uri de fiecare dată când împingeți, deoarece testele dvs. fac parte integrantă din fluxul de lucru al dezvoltării dvs. și, înainte de a vă împinge, veți fi deja conștienți de erori sau regresii. Dar acest lucru nu vă protejează neapărat de erorile care apar din testele de integrare (unde tot codul din mai multe sisteme este rulat împreună pentru a asigura că sistemul "ca întreg" funcționează corect).
Indiferent, codul nu trebuie să fie împins niciodată în mod direct la serverul de producție live; acesta ar trebui întotdeauna să fie împins mai întâi la un server CI pentru a ajuta la capturarea oricăror erori potențiale care apar din diferențele dintre mediul de dezvoltare și mediul de producție.
O mulțime de companii au încă mai multe medii pentru ca codul lor să treacă înainte de a ajunge la serverul de producție live.
De exemplu, la BBC News avem:
Deși fiecare mediu trebuie să fie identic în set-up, scopul este de a pune în aplicare diferite tipuri de teste pentru a se asigura că cât mai multe bug-uri sunt prinse și rezolvate înainte ca codul să ajungă "live".
Travis CI este un serviciu de integrare continuă găzduit pentru comunitatea open source. Este integrat cu GitHub și oferă suport de primă clasă pentru mai multe limbi
Ce inseamna acest lucru este faptul ca Travis-CI ofera servicii gratuite de CI pentru proiecte cu surse deschise si are, de asemenea, un model platit pentru companii si organizatii care doresc sa-si pastreze integrarea CI.
Vom folosi modelul open-source gratuit de pe magazia GitHub de exemplu.
Procesul este următorul:
.travis.yml
fișier în directorul rădăcină al proiectului dvs. și să îl angajați în depozitul dvs. GitHubPasul final este cel mai important (crearea unui .travis.yml
Fișier, deoarece aceasta determină setările de configurare pentru Travis-CI, astfel că știe cum să se ocupe de rularea testelor pentru proiectul dvs..
Să aruncăm o privire la .travis.yml
fișierul pe care îl folosim pentru depozitul GitHub de exemplu:
limbaj: rubin cache: bundler rvm: - 2.0.0 - 1.9.3 script: 'bundle exec rake spec' bundler_args: - fără ramuri de dezvoltare: numai: - notificări principale: email: - [email protected]
Să-l rupem în bucăți ...
Mai întâi specificăm ce limbă folosim în proiectul nostru. În acest caz, folosim Ruby: limba: rubin
.
Deoarece rulează Bundler poate fi un pic cam lent și știm că dependențele noastre nu se vor schimba, de multe ori putem alege să cache dependențele, așa că am stabilit cache: bundler
.
Travis-CI utilizează RVM (Ruby Version Manager) pentru a instala Rubies pe serverele lor. Așadar, trebuie să specificăm ce versiuni Ruby vrem să facem împotriva testelor noastre. În acest caz, am ales 2.0
și 1.9.3
care sunt două versiuni populare Ruby (tehnic aplicația noastră folosește Ruby 2, dar este bine de știut că codul nostru trece și în alte versiuni de Ruby):
rvm: - 2.0.0 - 1.9.3
Pentru a rula testele noastre știm că putem folosi comanda greblă
sau rake spec
. Travis-CI execută implicit comanda greblă
dar din cauza modului în care Gems sunt instalate pe Travis-CI folosind Bundler trebuie să schimbăm comanda implicită: script: 'bundle exec rake spec'
. Dacă nu am face asta, atunci Travis-CI ar avea o problemă de localizare rspec / core / rake_task
fișier care este specificat în cadrul nostru Rakefile
.
Notă: dacă aveți probleme cu privire la Travis-CI, puteți să vă alăturați canalului #travis pe freenode IRC pentru a vă ajuta să răspundeți la orice întrebări pe care le aveți. Acolo am descoperit soluția la problema mea, deoarece Travis-CI nu a reușit să-mi execute testele utilizând setările implicite greblă
comanda și sugestia de suprascriere a implicit cu pachetul exec
a rezolvat problema.
Apoi, pentru că suntem interesați doar de rularea testelor noastre, putem transmite argumente suplimentare Travis-CI pentru filtrarea pietrelor pe care nu dorim să le deranjăm instalarea. Deci, pentru noi dorim să excludem instalarea pietrelor grupate ca dezvoltare: bundler_args: - fără dezvoltare
(aceasta înseamnă că excludem pietre care sunt folosite cu adevărat pentru dezvoltarea și depanarea, cum ar fi Pry and Guard).
Este important să rețineți că, inițial, încărcam Pry în cadrul nostru spec_helper.rb
fişier. Acest lucru a provocat o problemă atunci când rulează codul pe Travis-CI, acum că excludem pietre de "dezvoltare". Așa că a trebuit să modific codul așa:
cereți "pry" dacă ENV ['APP_ENV'] == 'debug'
Puteți vedea că acum pietrea Pry este numai necesita
'ed dacă o variabilă de mediu de APP_ENV
este setat să se depaneze. În acest fel putem evita ca Travis-CI să arunce orice eroare. Acest lucru înseamnă că, atunci când executați codul local, va trebui să setați variabila de mediu dacă doriți să depanați codul utilizând Pry. Următoarele arată cum se poate face acest lucru într-o singură linie:
APP_ENV = debug && ruby lib / example.rb
Au mai fost două schimbări pe care le-am făcut și asta a fost pentru noi Gemfile
. Unul a fost acela de a clarifica ce pietre erau necesare pentru testare și care erau necesare dezvoltării, iar cealaltă era cerută în mod explicit de Travis-CI:
sursă "https://rubygems.org" grup: test do gem 'rake' gem 'rspec' grup de sfârșit: development gem 'guard' gem 'guard-rspec' gem 'pry' pas, următoarea bijuterie "pry-remote" bijuterie "pry-nav" sfârșitul
Privind la cele actualizate mai sus Gemfile
putem vedea că am mutat bijuteria RSpec într-un nou produs Test
grup, deci acum ar trebui să fie mai clar ce scop are fiecare bijuterie. Am adăugat și noi bijuterie de bijuterie
. Documentația Travis-CI prevede că acest lucru trebuie specificat în mod explicit.
Următoarea secțiune este opțională și vă permite să listați (sau lista neagră) anumite ramuri din depozit. Prin urmare, în mod implicit, Travis-CI va executa teste împotriva tuturor ramurilor dvs., cu excepția cazului în care vă spuneți altfel. În acest exemplu, spunem că nu vrem decât să fugă împotriva noastră maestru
ramură:
ramuri: numai: - master
Am putea să-i spunem să ruleze fiecare ramură "cu excepția" unei ramuri specifice, cum ar fi:
ramuri: cu excepția: - some_branch_I_dont_want_run
Secțiunea finală îi spune lui Travis CI unde să trimită notificări atunci când o construcție nu reușește sau reușește:
notificări: e-mail: - [email protected]
Puteți specifica mai multe adrese de e-mail dacă doriți:
notificări: email: - [email protected] - [email protected] - [email protected]
Puteți fi mai specific și specificați ce doriți să se întâmple fie cu un eșec sau cu un succes (de exemplu, mai mulți oameni vor fi interesați doar dacă testele nu reușesc, mai degrabă decât să primească un e-mail de fiecare dată când trec):
notificări: email: destinatari: - [email protected] on_failure: change on_success: niciodată
Exemplul de mai sus arată că destinatarul nu va primi niciodată un e-mail dacă testele trec, dar vor fi notificate în cazul în care starea eșecului se modifică (valoarea implicită pentru ambele este mereu
ceea ce înseamnă că veți fi întotdeauna notificat indiferent de rezultatul obținut).
Notă: când specificați explicit a on_failure
sau on_success
trebuie să mutați adresa de e-mail din interiorul destinatari
cheie.
Acesta este sfârșitul aspectului nostru cu două părți în RSpec, TDD și Pry.
În prima parte am reușit să scriem cererea noastră folosind procesul TDD și cadrul de testare RSpec. În această a doua jumătate am folosit și Pry pentru a arăta cum putem depana mai ușor o aplicație Ruby care rulează. În cele din urmă, am reușit să încercăm setările pentru a rula ca parte a unui server de integrare continuă utilizând serviciul Travis-CI.
Sperăm că acest lucru ți-a dat destul de mult gust, astfel că ești dornic să investighezi mai departe fiecare dintre aceste tehnici.