Mockito modul de a crea și bate joc

Crearea unui obiect bate joc începe cu un apel de a bate joc (clasa typeToMock, setările MockSettings). unde

  • tipul de clasă al mock'a viitorului - typeToMock
  • - Setări mock'a

Un apel tipic pentru a crea un Mocha este după cum urmează:

În această configurație mock'a inițializate implicit folosind Mockito.withSettings metodei (). implementare care returnează interfața setări. O setările interfeței de clasă bate joc de obiecte de două - org.mockito.MockSettings și org.mockito.mock.MockCreationSettings. Prima definește metodele mock'ov parametrii de configurare, a doua definește interfața de acces la acești parametri, fără posibilitatea schimbării. Prin urmare, valorile intrării în obiectul produs prin prima interfață, și toate celelalte clase funcționează cu parametrii prin a doua interfață, că nimic în ea nu este schimbat în mod accidental. Setările pot fi setate manual atunci când creați un obiect bate joc. În special, puteți specifica orice mock'a nume pentru a testa jurnalele de execuție au devenit mai clare.

La crearea mock'a, toate stubb'iruyutsya sale metode. Rezultatele apel Metoda determină obiectul Răspuns. Pentru metode de testare importante pe care le cere un raspuns obiect manual prin intermediul design-Mockito.when (Matcher) .thenAnswer (Raspuns). Pentru alte obiecte numite Răspuns implicit. Punerea în aplicare specifică este determinată, de asemenea, în setările mock'a de răspuns și poate fi înlocuită. Setarea implicită utilizată org.mockito.internal.stubbing.defaultanswers.GloballyConfiguredAnswer. Acest răspuns, la rândul său, a delegat punerea în aplicare a răspunsului de interogare, care este definit în obiectul de configurare globală, care a fost luată în considerare în articolul Mockito: Prelucrarea adnotări. În configurația ca org.mockito.internal.stubbing.defaultanswers.ReturnsEmptyValues ​​de punere în aplicare definite. care returnează valori nule pentru diferite tipuri de obiecte.

În plus, GloballyConfiguredAnswer. în Mockito. realizate mai multe implementări ale răspunsurilor, linkurile către aceste obiecte sunt stocate în org.mockito.Answers Enum'e. De asemenea, mai multe Mockito disponibile și punerea în aplicare internă a răspunsurilor, cum ar fi ReturnsEmptyValues ​​și ReturnsMoreEmptyValues. cerere și Ultimele delegații ReturnsEmptyValues ​​completează logica definiției mai multor tipuri de date. Faptul că ReturnsEmptyValues ​​returneaza null pentru toate obiectele, cu excepția unor implementări de colecții de primitivilor și ambalaje lor. La un moment dat, dezvoltatorii au decis să sprijine mai multe siruri de caractere și matrice, ci ca cineva care este probabil să aibă timp pentru a scrie teste, având în vedere specificul, apoi pur și simplu să actualizeze punerea în aplicare existente, nu este suficient. A fost necesar să se creeze un nou tip de răspuns ReturnsMoreEmptyValues. Răspuns nou este acum utilizat în punerea în aplicare a răspunsului ReturnsSmartNulls. care, în loc de a încerca să creeze și să se întoarcă nul mock'realizatsiyu acest tip.

Există, de asemenea, alte punerea în aplicare internă a răspunsurilor, dar nu este nimic interesant. Este de asemenea posibil să se specifice în setările obiectelor - studenții care vor fi notificate în momentul apelului metodei. Aceste obiecte pune în aplicare interfață org.mockito.MockSettings.InvocationListener.

Printre altele, clasa de bază setări are o metodă de auto-test, care acceptă argumentul clasei obiectului, care este planificat pentru a crea simulate și verifică capacitatea de a crea mock'a cu aceste setări. În cazul unei verificări de succes, o nouă instanță a setărilor obiectului, care a stabilit numele obiectului și setările mock'a prelucrate definite anterior. numit Mocha interfață obiect org.mockito.internal.util.MockName utilizat pentru a stoca numele de Mocha și de a efectua anumite operațiuni de prelucrare numite Moka.

Obiectul principal al sistemului, creați un obiect care implementeaza interfata org.mockito.plugins.MockMaker. dar în mod direct cu acest obiect este clasa doar utilitar org.mockito.internal.util.MockUtil. Este o metodă de clasă numită în MockUtil createMock MockitoCore # bate joc. Primul obiect este creat cu org.mockito.invocation.MockHandler interfață. care intercepteaza metode apelul stabbirovannyh în obiectul bate joc. Obiecte interceptoare sunt fabrica org.mockito.internal.handler.MockHandlerFactory. Creează o implementare de bază handler org.mockito.internal.handler.MockHandlerImpl și diferite transformă wrapper'ami (model Wrapper) pentru atașarea funcționalitate suplimentară. În acest moment, înveliș următoarele:

  • nuluri org.mockito.internal.handler.NullResultGuardian pentru a preveni valorile de retur ale metodelor care returnează tipurile primitive sau ambalajele acestora.
  • org.mockito.internal.handler.MockHandlerFactory notifică ascultătorii declarate în setările apelului metodei.

Metoda Următoarea este numită MockMaker # createMock. în cazul în care sunt transferate și MockHandler setările. MockMaker'a obiect este creat într-un câmp de clasă statică MockUtil folosind ClassPathLoader. care a fost folosit pentru a descărca de configurare personalizată clasa de implementare. Metoda SlassPathLoader # getMockMaker returnează un MockMaker'a de punere în aplicare de pre-încărcate. Precum și cu configurația obiect, este posibil să se utilizeze MockMaker'a meu de punere în aplicare. dar de încărcare principiul este diferit:

Cu ClassLoader'a fișier descărcat cu numele clasei a trecut la argumentul serviciului. În momentul de față, deoarece serviciul este utilizat clasa MockMaker. Fișierul este căutat în dosarul numit „Mockito-extensii“. Fișierul conține numele complete ale claselor - o clasă pe linie. Mai mult, aceste clase sunt încărcate și obiectele lor. În ciuda capacității de a încărca mai multe MockMaker'ov. Acesta va fi aplicat numai primei găsite. În cazul în care clasa de utilizator nu este prezent, implicit boot-MockMaker org.mockito.internal.creation.CglibMockMaker.

Creați clase proxy și obiect bate joc și, de fapt, ele sunt în mod implicit furnizate de bibliotecă CGLib. Surse ale bibliotecii incluse în proiect, astfel încât să nu deranjez cu versiunea proiectului și sursa de reambalare. Desigur, Maven ar facilita sarcina și structura de proiect va deveni mai clar, dar ce-a făcut. Dezvoltatorii nu modifica codul sursă și în ansamblul său este interzisă. CGLib - bibliotecă, permițându-vă să creați, să se extindă clasele și interfețele în runtime'e.

În interiorul MockMaker „metode handler apel stabbirovannyh - MockHandler se transformă în clasa MethodInterceptorFilter. MethodInterceptor implementeaza interfata. care face parte din biblioteca CGLib.

Destul de ciudat, logica de a crea obiecte folosind CGLib neclare și este descrisă într-o anumită clasă de org.mockito.internal.creation.jmock.ClassImposterizer utilitare. care a fost deja folosit la setările de verificare mock'obekta. Această clasă este împrumutată de la biblioteca jMock.

#Thanks la baieti jMock pentru această clasă la îndemână, care înfășoară toate magia cglib.

Această clasă introduce eterogenitate în Mockito. este foarte urât. De exemplu, pentru a crea instanțe de clasă utilizate objenesis bibliotecă. În Mockito ca această procedură se realizează în mod direct, folosind reflecție.

În primul rând seta vizibilitatea designeri, care creează o clasă pentru obiect Mock. Am trecut deja. Rezolvat metode de reflexie pereche. Apoi, creați un obiect de clasă proxy. Acest lucru se realizează cu ajutorul CGLib clasa Enhancer. Această clasă construiește clasa pentru proxy viitoare în parametrii pe care le-am transferat la ea.

Am renunțat la unele puncte de pe clase sekyurnostyu și gestionarea de manipulare excepție. Ele sunt nesemnificative.

Pentru a începe să rezolve problema cu un bug CGLib. care refuză să se ocupe de obiect de clasă. pentru că undeva, probabil legat de clasa părinte. Ie în cazul în care tipul de obiect machetă - obiect. vom crea un ClassWithSuperclassToWorkAroundCglibBug obiect gol. care lucrează în continuare. Apoi a crea Enhancer'a obiect. și el a trecut clase viitoare classloader'y mock'ov înfășurat în clasa interioară CGLib pentru a lucra cu toate classloader'ami găsit ca unul. Clasa de, printre altele, se va pune în aplicare interfața Factory. care definește metodele de apeluri de metode de instalare handler și instanțierea acestor obiecte. Aceasta este o caracteristică internă CGLib. Alte puncte tipuri Enhancer'u de clase și interfețe pe care el va moșteni, și tipuri de metode de procesoare interceptor. În acest caz, clasele MethodInterceptor standard. care vă permite să definiți și noop stivuitoare. care transmite metodele de gestionare a obiectelor direct - aveți nevoie pentru a spiona mokov.

Următorul pas este de a crea un obiect proxy:

După cum se poate observa, objensis simplifică foarte mult crearea de obiecte. Dezvoltatorii se pare că nu au ajuns în mâinile pentru a re-scrie cod folosind această bibliotecă. Ca manipulare eveniment specificați InternalMockHandler creat anterior și punerea în aplicare de interfață de noop.

Acum rămâne doar să informeze toate componentele evenimentului crearea Mocha:

și a reveni la testul de clasă.

Am act de faptul că o mulțime de cod codificați. Există multe locuri în care metoda ia parametrii de o interfață și obiect comun în cadrul metodei este verificat pentru conformitatea cu un anumit tip care implementează această interfață:

Dar merită să plătească tribut pentru dezvoltatorii pentru îngrijirea utilizatorilor - extinderea proiectului, ei nu încearcă să schimbe vechea parte a API-ului. Este o rușine că ar fi de a rescrie o grămadă de teste în timpul trecerii la noua versiune Mockito.