CodeGym /Java Blog /Random /Unit Testing sa Java gamit ang JUnit
John Squirrels
Antas
San Francisco

Unit Testing sa Java gamit ang JUnit

Nai-publish sa grupo

Ano ang unit testing sa Java?

Bago natin matutunan ang JUnit sa Java, tingnan natin sandali kung ano ang unit testing at kung bakit ito napakapopular (kung alam mo na ang bagay na ito, lumaktaw sa 'Paano ako magsusulat ng JUnit Test sa Java?'). Ang pagsubok sa unit sa Java ay ginagawang mas mahusay at walang hirap ang malakihang pagbuo ng software. Makakatulong ito sa parehong mga indibidwal, at mga koponan na maputol ang hindi mabilang na oras sa pag-debug at i-streamline nang husto ang proseso ng pakikipagtulungan. Unit Testing sa Java na may JUnit - 1

https://junit.org/junit4/

Ang mahalagang ideya ng unit testing ay ito: sumulat ng mga atomic na pagsubok ng mga indibidwal na feature (tinatawag na unit test) at dahan-dahang magdagdag ng higit pang mga feature pagkatapos ng pagsubok at pagtiyak na gumagana ang mga nauna. Ito ay isang napakasimple ngunit makapangyarihang ideya. Bilang isang halimbawa kung ano ang magiging hitsura ng prosesong ito, isipin na gumagawa ka ng isang virtual na siyentipikong calculator. Sa itaas ng maliwanag na mga operator ng arithmetic ( +, -, x, %), ang calculator na ito ay magkakaroon ng mga advanced na feature na nangangailangan ng ibang mga subfeature na gumana sa loob nito. Upang kalkulahin ang mga exponent, kailangang makapag-multiply nang tama ang iyong calculator. Kaya ang isang unit testing approach sa pagbuo at pagsubok sa calculator na ito ay:
  • Sumulat ng karagdagan function. Subukan itong mabuti, baguhin ito, ulitin hanggang sa ito ay gumana.
  • Gawin ang parehong para sa pagbabawas, pagpaparami, mga function ng paghahati.
  • Gamitin ang mga base operator na ito upang magsulat ng mas advanced na mga function ng operator tulad ng mga exponents, pagkatapos ay subukan din ang mga function na iyon.
Tinitiyak nito na ang mga feature na bumubuo sa iba pang maliliit na subfeature ay hindi lamang gumagana nang maayos sa kanilang sariling karapatan ngunit walang mga sira na subfeature sa loob nito. Halimbawa, kung sinusubukan ko ang exponent function at may nangyayaring mali, alam kong malamang na wala ang bug sa multiplication subfeature, dahil ang multiplication function ay nasubok nang husto. Ito ay lubos na nag-aalis ng kabuuang halaga ng code na kailangan kong i-backtrace at siyasatin upang mahanap ang bug. Sana, nililinaw ng maliit na halimbawang ito kung paano nakaayos ang proseso ng pag-iisip sa paligid ng Pagsusuri ng Unit. Ngunit paano nakikipag-ugnayan ang pagsubok sa unit sa natitirang bahagi ng proseso ng pagbuo ng software? Paano kung mayroon kang mas kumplikadong mga tampok, na kailangang makapagtrabaho at makipag-usap nang magkasama? Ang pagsubok sa unit ay hindi sapat upang matiyak na ang mga kumplikadong tampok ay maaaring gumana nang maayos nang magkasama. Sa katunayan, ito ay unang hakbang pa lamang ng Apat na Antas ng Pagsusuri ng Software (Gumagamit ako ng malalaking titik dahil tinutukoy ko ang pamantayan ng industriya o ang pinakakaraniwang diskarte sa pagsubok ng software). Ang huling tatlong hakbang ayPagsusuri sa Pagsasama , Pagsusuri ng System , at Pagsusuri sa Pagtanggap. Ang lahat ng ito ay malamang na eksaktong ibig sabihin kung ano sa tingin mo ang ginagawa nila, ngunit hayaan mo akong linawin: Ang pagsubok sa pagsasama ay kung ano ang gagawin namin upang matiyak ang mga nabanggit sa itaas, "mga kumplikadong tampok," na maayos na nakikipag-ugnayan sa isa't isa. (hal., tinitiyak na kaya ng calculator ang “3 + 7 * 4 - 2”) Sinusubok ng system testing ang pangkalahatang disenyo ng isang partikular na system; madalas mayroong maraming system ng mga kumplikadong feature na nagtutulungan sa isang produkto, kaya igrupo mo ang mga ito sa mga system at subukan ang mga ito nang paisa-isa. (hal. kung gagawa ka ng graphing calculator, bubuo ka muna ng aritmetika na 'system' para harapin ang mga numero, pagsubok hanggang sa gumana ito ayon sa nilalayon, at pagkatapos ay bubuo at susubukan mo ang graphing 'system' para harapin ang pag-withdraw, gaya ng ito ay bubuo sa arithmetic system). Ang pagsubok sa pagtanggap ay pagsubok sa antas ng gumagamit; tinitingnan nito kung ang lahat ng system ay maaaring gumana nang naka-sync upang lumikha ng isang tapos na produkto na handang tanggapin ng mga user (hal., ang mga user na sumusubok sa calculator). Minsan ay maaaring balewalain ng mga developer ng software ang panghuling hakbang na ito ng proseso, dahil madalas na ang iba pang empleyado ay magde-deploy ng user (beta) na mga pagsubok nang hiwalay.

Paano ako magsusulat ng JUnit test sa Java?

Ngayon na mayroon ka nang mas malinaw na ideya ng mga benepisyo at limitasyon ng pagsubok sa unit, tingnan natin ang ilang code! Gagamit kami ng isang sikat na balangkas ng pagsubok sa Java na tinatawag na JUnit (isa pang sikat ay ang TestNG, na maaari mo ring gamitin kung gusto mo. Ang mga ito ay halos magkapareho, ayon sa syntactically; TestNG ay inspirasyon ng JUnit). Maaari mong i-download at i-install ang JUnit dito . Para sa halimbawang code na ito, magpapatuloy tayo sa halimbawa ng 'scientific calculator' na binanggit ko kanina; ito ay medyo simple upang ibalot ang iyong ulo sa paligid, at ang test code ay napakadali. Ang karaniwang pagsasanay ay ang pagsulat ng magkakahiwalay na klase ng pagsubok para sa bawat isa sa iyong mga klase, kaya iyon ang gagawin namin. Ipagpalagay natin na sa puntong ito, mayroon kaming isang Math.javafile na may lahat ng mga function ng matematika sa loob nito (kabilang ang Math.add), at nagsusulat kami ng isangMathTests.javafile sa parehong pakete. Ngayon, mag-set up tayo ng mga import statement at class body: (POSSIBLE JUnit INTERVIEW QUESTION: Maaaring tanungin ka kung saan ilalagay ang iyong JUnit test at kung kailangan mo o hindi na i-import ang iyong source file. Kung isinusulat mo ang iyong mga test class sa parehong package bilang ang iyong mga pangunahing klase, pagkatapos ay hindi mo kailangan ng anumang mga pahayag sa pag-import para sa iyong mga source file sa pagsubok na klase. Kung hindi, siguraduhing ini-import mo ang iyong mga source file!)

import org.junit.jupiter.Test;    //gives us the @Test header
import static org.junit.jupiter.api.Assertions.assertEquals; //less typing :) 

public class MathTests {
	//...
}
Ang unang pahayag ng pag-import ay nagbibigay sa amin ng @Testheader. @TestDirektang sinusulat namin ang ' ' sa ibabaw ng bawat kahulugan ng function ng pagsubok, upang malaman ng JUnit na isa itong singular na unit test na maaaring patakbuhin nang hiwalay. Sa bandang huli, ipapakita ko sa iyo kung paano ka makakapagpatakbo ng mga partikular na unit test gamit ang header na ito. Ang pangalawang pahayag ng pag-import ay nakakatipid sa amin ng kaunting pag-type. Ang pangunahing JUnit function na ginagamit namin upang subukan ang aming mga function ay to Assert.assertEquals(), na kumukuha ng dalawang parameter (aktwal na halaga at inaasahang halaga) at tinitiyak na pantay ang mga ito. Ang pagkakaroon ng pangalawang pahayag ng pag-import na ito ay nagbibigay-daan sa amin na mag-type lamang ng ' assertEquals(...' sa halip na tukuyin sa bawat oras kung aling pakete ito ay bahagi. Ngayon, magsulat tayo ng napakasimpleng test case para ma-verify na ang 2 + 2 ay talagang 4!

import org.junit.jupiter.Test; // gives us the @Test header
import static org.junit.jupiter.api.Assertions.assertEquals; // less typing :) 


public class MathTests {
	@Test
	public void add_twoPlusTwo_returnsFour(){
	final int expected = 4;
	final int actual = Math.add(2, 2);
	assertEquals(“2+2 is 4”, actual, expected);
	}
}
Tingnan natin ang bawat isa sa limang linya ng function ng pagsubok at kung ano ang ginagawa ng mga ito: Linya 5: @TestTinutukoy ng header na ito na ang kahulugan ng function sa ibaba add_twoPlusTwo_returnsFour()ay talagang isang function ng pagsubok na maaaring patakbuhin ng JUnit nang hiwalay. Linya 6: Ito ang function signature para sa aming test case. Ang mga kaso ng pagsubok ay palaging napaka-isahan; sumubok lamang sila ng isang partikular na halimbawa, gaya ng 2+2=4. Karaniwang pangalanan ang iyong mga test case sa form na “ [function]_[params]_returns[expected](),” kung saan [function]ang pangalan ng function na iyong sinusubok, [params]ang mga partikular na halimbawang parameter na iyong sinusubok, at [expected]ang inaasahang return value ng function. Ang mga function ng pagsubok ay halos palaging may uri ng pagbabalik na ' void' dahil ang pangunahing punto ng buong function ay upang tumakboassertEquals, na maglalabas sa console kung pumasa man o hindi ang iyong pagsubok; hindi mo na kailangan ang anumang iba pang data upang maibalik kahit saan. Linya 7: Nagdedeklara kami ng ' final' variable ng uri ng pagbabalik ng Math.add (int), at pinangalanan itong 'inaasahan' ayon sa convention. Ang halaga nito ay ang sagot na aming inaasahan (4). Linya 8: Nagdedeklara kami ng ' final' variable ng uri ng pagbabalik ng Math.add (int), at pinangalanan itong 'aktwal' ayon sa convention. Ang halaga nito ay bunga ng Math.add(2, 2). Linya 9: Ang gintong linya. Ito ang linyang naghahambing ng aktuwal at inaasahan at nagsasabi sa amin na nakapasa lang kami sa pagsusulit kung pantay ang mga ito. Ang unang parameter na naipasa na "2+2 ay 4" ay isang paglalarawan ng test function.

Paano kung ang aking function ay dapat magtapon ng isang pagbubukod?

Kung ang iyong partikular na halimbawa ng pagsubok ay dapat maghagis ng isang pagbubukod sa halip na igiit na ang isang aktwal at inaasahang halaga ay pantay, kung gayon ang JUnit ay may paraan ng paglilinaw nito sa @Testheader. Tingnan natin ang isang halimbawa sa ibaba. Ipagpalagay na mayroon kaming isang function sa Math.javatinatawag na Math.divide, gusto naming tiyakin na ang mga input ay hindi mahahati sa 0. Sa halip, ang pagsubok na tumawag Math.divide(a, 0)para sa anumang halaga ng 'a' ay dapat magtapon ng exception ( ArithmeticException.class). Tinukoy namin ito sa header tulad ng:

import org.junit.jupiter.Test; // gives us the @Test header
import static org.junit.jupiter.api.Assertions.assertEquals; // less typing :) 


public class MathTests {
	@Test (expectedExceptions = ArithmeticException.class)
	public void divide_byZero_throwsException() throws ArithmeticException{
	Math.divide(1, 0);
	}
}
Maaari kang magkaroon ng higit sa isang pagbubukod para sa expectedExceptions, tiyaking gumamit ng mga bracket at kuwit upang ilista ang iyong mga klase ng pagbubukod, tulad nito:

expectedException = {FirstException.class, SecondException.class, … }

Paano ko papatakbuhin ang aking mga pagsusulit sa JUnit sa Java?

Paano magdagdag ng JUnit sa IntelliJ: https://stackoverflow.com/questions/19330832/setting-up-junit-with-intellij-idea Maaari mong patakbuhin ang iyong proyekto gaya ng karaniwan mong pinapatakbo ang mga pagsubok. Ang pagpapatakbo ng lahat ng mga pagsubok sa isang klase ng pagsubok ay tatakbo sa kanila sa alpabetikong pagkakasunud-sunod. Sa JUnit 5, maaari kang magdagdag ng priyoridad sa mga pagsubok sa pamamagitan ng pagdaragdag ng @Ordertag. Isang halimbawa:

@TestMethodOrder(OrderAnnotation.class)
public class Tests {
…
@Test
@Order(2)
public void a_test() { … }

@Test
@Order (1)
public void b_test() { … }
…
}
Kahit na a_test()nauuna sa b_test()alphabetically at sa code, b_test()ay tatakbo bago a_test()dito, dahil 1 ay nauuna sa 2 sa Order. Kaya iyon ay tungkol sa lahat para sa mga pangunahing kaalaman ng JUnit. Ngayon, talakayin natin ang ilang karaniwang Mga Tanong sa Panayam sa JUnit, at alamin ang higit pa tungkol sa JUnit habang nasa daan!

Mga Tanong sa Panayam ng JUnit (Karagdagang Impormasyon)

Dito ko nakolekta ang pinakasikat na mga tanong sa panayam ng JUnit. Kung mayroon kang idaragdag — huwag mag-atubiling gawin ito sa mga komento sa ibaba. T: Anong paraan ang maaari mong tawagan sa iyong paraan ng pagsubok upang awtomatikong mabigo sa isang pagsubok? A: fail("error description here!"); T: Sinusubukan mo ang klase ng Aso; upang subukan ang isang bagay ng Aso, kailangan mong i-instantiate ito bago ka makapagsagawa ng mga pagsubok dito. Kaya't sumulat ka ng isang setUp() function upang ma-instantiate ang Aso. Gusto mo lang patakbuhin ang function na ito nang isang beses sa lahat ng pagsubok. Ano ang dapat mong ilagay nang direkta sa itaas ng setUp() function signature para malaman ng JUnit na magpatakbo ng setUp() bago patakbuhin ang mga pagsubok? A: @BeforeClass (@BeforeAll sa JUnit 5) T:Ano dapat ang function signature ng setUp() function na inilarawan sa itaas? A: pampublikong static na walang bisa. Ang anumang function na may @BeforeClass (@BeforeAll sa JUnit 5) o @AfterClass (@AfterAll sa JUnit 5) ay kailangang static. T: Tapos ka na sa pagsubok sa klase ng Aso. Sumulat ka ng void tearDown() function na naglilinis ng data at nagpi-print ng impormasyon para ma-console pagkatapos ng bawat pagsubok. Gusto mong tumakbo ang function na ito pagkatapos ng bawat pagsubok. Ano ang dapat mong ilagay nang direkta sa itaas ng tearDown() function signature para malaman ng JUnit na magpatakbo ng tearDown() pagkatapos patakbuhin ang bawat pagsubok? A: @After (@AfterEach sa JUnit 5)
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION