CodeGym /Blog Jawa /Acak /Kabeh babagan pengujian unit: teknik, konsep, praktik
John Squirrels
tingkat
San Francisco

Kabeh babagan pengujian unit: teknik, konsep, praktik

Diterbitake ing grup
Dina iki, sampeyan ora bakal nemokake aplikasi sing ora ana tes, mula topik iki bakal luwih relevan tinimbang sadurunge kanggo pangembang pemula: sampeyan ora bisa sukses tanpa tes. Ayo dipikirake apa jinis tes sing digunakake ing prinsip, banjur kita bakal sinau kanthi rinci kabeh sing kudu dingerteni babagan tes unit. Kabeh babagan pengujian unit: teknik, konsep, praktik - 1

Jinis tes

Apa iku tes? Miturut Wikipedia: "Pengujian piranti lunak kalebu eksekusi komponen piranti lunak utawa komponen sistem kanggo ngevaluasi siji utawa luwih properti sing dikarepake." Ing tembung liyane, iku mriksa bener sistem kita ing kahanan tartamtu. Inggih, ayo ndeleng apa jinis tes umume:
  • Pengujian unit - Tes sing tujuane kanggo mriksa saben modul sistem kanthi kapisah. Tes kasebut kudu ditrapake kanggo bagean atom paling cilik saka sistem, contone, modul.
  • Tes sistem - Tes tingkat dhuwur kanggo mriksa operasi bagean aplikasi utawa sistem kanthi sakabehe.
  • Tes regresi - Tes sing digunakake kanggo mriksa apa fitur anyar utawa koreksi bug mengaruhi fungsi aplikasi sing wis ana utawa ngenalake bug lawas.
  • Pengujian fungsional - Priksa manawa bagean saka aplikasi kasebut nyukupi syarat sing kasebut ing spesifikasi, crita pangguna, lsp.

    Jenis tes fungsional:

    • Tes kothak putih - Priksa manawa bagean saka aplikasi nyukupi syarat nalika ngerti implementasine internal sistem;
    • Pengujian kothak ireng - Priksa manawa bagean saka aplikasi nyukupi syarat tanpa ngerti implementasine internal sistem.

  • Pengujian kinerja - Tes sing ditulis kanggo nemtokake cara sistem utawa bagean sistem nindakake ing beban tartamtu.
  • Pengujian beban - Tes sing dirancang kanggo mriksa stabilitas sistem ing beban standar lan nemokake beban maksimal nalika aplikasi isih bisa digunakake kanthi bener.
  • Tes stres - Tes sing dirancang kanggo mriksa kinerja aplikasi ing beban sing ora standar lan kanggo nemtokake beban maksimal sadurunge gagal sistem.
  • Tes keamanan - Tes sing digunakake kanggo mriksa keamanan sistem (saka peretas, virus, akses ora sah menyang data rahasia, lan serangan liyane sing nyenengake).
  • Tes lokalisasi - Tes lokalisasi aplikasi.
  • Tes Usability - Tes kanggo mriksa kegunaan, dingerteni, daya tarik, lan sinau.
Iki kabeh muni apik, nanging carane iku bisa ing laku? Prasaja! Kita nggunakake piramida testing Mike Cohn: Kabeh babagan pengujian unit: teknik, konsep, praktik - 2Iki versi simplified saka piramida: iku saiki dipérang dadi bagéan malah cilik. Nanging dina iki kita ora bakal dadi canggih. Kita bakal nimbang versi paling gampang.
  1. Unit - Bagean iki nuduhake tes unit, sing ditrapake ing macem-macem lapisan aplikasi. Dheweke nyoba unit logika aplikasi sing paling cilik sing bisa dibagi. Contone, kelas, nanging paling asring cara. Tes kasebut biasane nyoba ngisolasi apa sing dites saka logika eksternal. Yaiku, dheweke nyoba nggawe ilusi manawa aplikasi liyane mlaku kaya sing dikarepake.

    Mesthi ana akeh tes kasebut (luwih saka jinis liyane), amarga padha nyoba potongan-potongan cilik lan entheng banget, ora nggunakake akeh sumber daya (tegese RAM lan wektu).

  2. Integrasi - Bagean iki nuduhake tes integrasi. Pengujian iki mriksa potongan sistem sing luwih gedhe. Sing, iku salah siji nggabungke sawetara bagéyan logika (sawetara cara utawa kelas), utawa mriksa bener saka interaksi karo komponen external. Tes iki biasane luwih cilik tinimbang tes unit amarga luwih abot.

    Conto tes integrasi bisa uga nyambungake menyang database lan mriksa kebeneran operasi metode kanggo nggarap.

  3. UI - Bagean iki nuduhake tes sing mriksa operasi antarmuka pangguna. Dheweke melu logika ing kabeh level aplikasi, mula uga diarani tes end-to-end. Minangka aturan, ana luwih sithik, amarga paling rumit lan kudu mriksa dalan sing paling dibutuhake (digunakake).

    Ing gambar ing ndhuwur, kita bisa ndeleng manawa macem-macem bagean segitiga beda-beda ukurane: kira-kira proporsi sing padha ana ing macem-macem jinis tes ing karya nyata.

    Dina iki kita bakal nliti tes sing paling umum, tes unit, amarga kabeh pangembang Java sing ngurmati awake dhewe kudu bisa digunakake ing tingkat dhasar.

Konsep kunci ing tes unit

Jangkoan tes (jangkoan kode) minangka salah sawijining ukuran utama babagan carane aplikasi diuji. Iki minangka persentase kode sing dilindhungi dening tes (0-100%). Ing praktik, akeh sing ngupayakake persentase iki minangka tujuane. Iku soko aku ora setuju karo, awit iku tegese tes wiwit Applied ngendi padha ora perlu. Contone, umpamane kita duwe operasi CRUD standar (gawe / entuk / nganyari / mbusak) ing layanan kita tanpa logika tambahan. Cara iki sejatine perantara sing utusan karya menyang lapisan sing nggarap repositori. Ing kahanan iki, kita duwe apa-apa kanggo nyoba, kajaba mbok menawa cara diwenehi nelpon cara DAO, nanging iku guyon. Piranti tambahan biasane digunakake kanggo netepake jangkoan tes: JaCoCo, Cobertura, Clover, Emma, ​​lsp. Kanggo sinau sing luwih rinci babagan topik iki, TDD stands for testing-driven development. Ing pendekatan iki, sadurunge nindakake tindakan liya, sampeyan nulis tes sing bakal mriksa kode tartamtu. Iki dadi tes kothak ireng: kita ngerti input kasebut lan kita ngerti apa output kasebut. Iki ndadekake iku bisa kanggo ngindhari duplikasi kode. Pangembangan adhedhasar uji coba diwiwiti kanthi ngrancang lan ngembangake tes kanggo saben fungsi ing aplikasi sampeyan. Ing pendekatan TDD, kita nggawe test pisanan sing nemtokake lan nguji prilaku kode kasebut. Tujuan utama TDD yaiku nggawe kode sampeyan luwih gampang dingerteni, luwih gampang, lan bebas kesalahan. Kabeh babagan pengujian unit: teknik, konsep, praktik - 3Pendekatan kasebut kalebu ing ngisor iki:
  • Kita nulis tes kita.
  • We mbukak test. Ora kaget, gagal, amarga kita durung ngetrapake logika sing dibutuhake.
  • Tambah kode sing nyebabake tes kasebut lulus (kita nglakokake tes maneh).
  • We refactor kode.
TDD adhedhasar tes unit, amarga minangka blok bangunan paling cilik ing piramida otomatisasi tes. Kanthi tes unit, kita bisa nyoba logika bisnis saka kelas apa wae. BDD stands for behavior-driven development. Pendekatan iki adhedhasar TDD. Luwih khusus, nggunakake conto basa sing jelas sing nerangake prilaku sistem kanggo kabeh wong sing melu pembangunan. Kita ora bakal nyelidiki istilah iki, amarga utamane mengaruhi penguji lan analis bisnis. Kasus uji minangka skenario sing nggambarake langkah-langkah, kondisi tartamtu, lan paramèter sing dibutuhake kanggo mriksa kode sing dites. Perlengkapan tes yaiku kode sing nyiyapake lingkungan tes supaya kahanan sing dibutuhake supaya metode sing diuji bisa sukses. Iki minangka kumpulan obyek sing wis ditemtokake lan prilaku ing kahanan tartamtu.

Tahap tes

Tes kasusun saka telung tahap:
  • Nemtokake data tes (perlengkapan).
  • Ngleksanani kode ing test (telpon cara dites).
  • Verifikasi asil lan mbandhingake karo asil samesthine.
Kabeh babagan pengujian unit: teknik, konsep, praktik - 4Kanggo njamin modularitas tes, sampeyan kudu ngisolasi saka lapisan aplikasi liyane. Iki bisa ditindakake kanthi nggunakake rintisan, moyoki, lan mata-mata. Mocks minangka obyek sing bisa disesuaikan (contone, disesuaikan kanggo saben tes). Dheweke ngidini kita nemtokake apa sing dikarepake saka telpon metode, yaiku tanggapan sing dikarepake. Kita nggunakake obyek mock kanggo verifikasi manawa kita entuk apa sing dikarepake. Rintisan menehi respon hard-kode kanggo telpon sak testing. Dheweke uga bisa nyimpen informasi babagan telpon (contone, paramèter utawa nomer telpon). Iki kadhangkala disebut mata-mata. Kadhangkala wong mbingungake istilah rintisan lan moyoki: bedane yaiku stub ora mriksa apa-apa - mung simulasi negara tartamtu. Mock minangka obyek sing nduweni pangarep-arep. Contone, yen cara tartamtu kudu disebut kaping tartamtu. Ing tembung liya,

Lingkungan tes

Dadi, saiki menyang titik. Ana sawetara lingkungan test (kerangka) kasedhiya kanggo Jawa. Sing paling populer yaiku JUnit lan TestNG. Kanggo review ing kene, kita nggunakake: Kabeh babagan pengujian unit: teknik, konsep, praktik - 5Tes JUnit minangka cara ing kelas sing mung digunakake kanggo tes. Kelas kasebut biasane dijenengi padha karo kelas sing dites, kanthi "Test" ditambahake ing pungkasan. Contone, CarService -> CarServiceTest. Sistem mbangun Maven kanthi otomatis kalebu kelas kasebut ing ruang tes. Nyatane, kelas iki diarani kelas tes. Ayo dadi ringkes babagan anotasi dhasar:

  • @Test nuduhake yen metode kasebut minangka tes (sejatine, metode sing ditandhani karo anotasi iki minangka tes unit).
  • @Before tegese cara sing bakal ditindakake sadurunge saben tes. Contone, kanggo populate kelas karo data test, maca data input, etc.
  • @After digunakake kanggo menehi tandha cara sing bakal diarani sawise saben test (contone kanggo mbusak data utawa mulihake nilai standar).
  • @BeforeClass diselehake ing ndhuwur metode, analog karo @Before. Nanging cara kasebut mung diarani sapisan sadurunge kabeh tes kanggo kelas sing diwenehake lan mulane kudu statis. Iki digunakake kanggo nindakake operasi sing luwih intensif sumber daya, kayata muter basis data tes.
  • @AfterClass minangka kebalikan saka @BeforeClass: dieksekusi sapisan kanggo kelas sing diwenehake, nanging mung sawise kabeh tes. Iki digunakake, contone, kanggo mbusak sumber daya sing terus-terusan utawa medhot saka database.
  • @Ignore nuduhake yen cara dipatèni lan bakal digatèkaké sak test run sakabèhé. Iki digunakake ing macem-macem kahanan, contone, yen cara dhasar wis diganti lan test durung reworked kanggo nampung owah-owahan. Ing kasus kaya mengkono, iku uga seng di pengeni kanggo nambah gambaran, Ie @Ignore("Sawetara gambaran").
  • @Test (dikarepake = Exception.class) digunakake kanggo tes negatif. Iki minangka tes sing verifikasi kepiye cara tumindak yen ana kesalahan, yaiku, tes kasebut ngarepake metode kasebut bakal mbuwang sawetara pengecualian. Cara kasebut dituduhake kanthi anotasi @Test, nanging kanthi indikasi kesalahan sing bakal ditindakake.
  • @Test (wektu entek = 100) mriksa manawa metode kasebut dieksekusi ora luwih saka 100 milidetik.
  • @Mock digunakake ing ndhuwur lapangan kanggo nemtokake obyek mock (iki dudu anotasi JUnit, nanging asale saka Mockito). Yen perlu, kita nyetel prilaku mock kanggo kahanan tartamtu langsung ing cara test.
  • @RunWith (MockitoJUnitRunner.class) diselehake ing ndhuwur kelas. Anotasi iki ngandhani JUnit supaya njaluk tes ing kelas. Ana macem-macem pelari, kalebu: MockitoJUnitRunner, JUnitPlatform, lan SpringRunner. Ing JUnit 5, anotasi @RunWith wis diganti karo anotasi @ExtendWith sing luwih kuat.
Ayo goleki sawetara cara sing digunakake kanggo mbandhingake asil:

  • assertEquals(Objek samesthine, Obyek aktual) - mriksa apa obyek liwati padha.
  • assertTrue(boolean flag) - mriksa apa nilai liwati bener.
  • assertFalse(boolean flag) - mriksa apa nilai liwati iku palsu.
  • assertNull (Obyek obyek) - mriksa apa obyek liwati null.
  • assertSame(Object firstObject, Object secondObject) - mriksa apa nilai sing dilewati nuduhake obyek sing padha.
  • negesake Sing (T t, Matcher tukang tandhing) - Priksa apa t marem kondisi kasebut ing matcher.
AssertJ uga nyedhiyakake cara perbandingan sing migunani: assertThat(firstObject).isEqualTo(secondObject) . Ing kene aku wis nyebutake cara dhasar - liyane yaiku variasi saka ndhuwur.

Testing ing laku

Saiki ayo ndeleng materi ing ndhuwur ing conto tartamtu. Kita bakal nyoba cara nganyari layanan. Kita ora bakal nimbang lapisan DAO, amarga kita nggunakake standar. Ayo nambah wiwitan kanggo tes:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <version>2.2.2.RELEASE</version>
   <scope>test</scope>
</dependency>
Lan ing kene kita duwe kelas layanan:

@Service
@RequiredArgsConstructor
public class RobotServiceImpl implements RobotService {
   private final RobotDAO robotDAO;

   @Override
   public Robot update(Long id, Robot robot) {
       Robot found = robotDAO.findById(id);
       return robotDAO.update(Robot.builder()
               .id(id)
               .name(robot.getName() != null ? robot.getName() : found.getName())
               .cpu(robot.getCpu() != null ? robot.getCpu() : found.getCpu())
               .producer(robot.getProducer() != null ? robot.getProducer() : found.getProducer())
               .build());
   }
}
Baris 8 - narik obyek sing dianyari saka database. Baris 9-14 - nggawe obyek liwat pembangun. Yen obyek sing mlebu duwe lapangan, atur. Yen ora, kita bakal ninggalake apa sing ana ing database. Saiki deleng tes kita:

@RunWith(MockitoJUnitRunner.class)
public class RobotServiceImplTest {
   @Mock
   private RobotDAO robotDAO;

   private RobotServiceImpl robotService;

   private static Robot testRobot;

   @BeforeClass
   public static void prepareTestData() {
       testRobot = Robot
               .builder()
               .id(123L)
               .name("testRobotMolly")
               .cpu("Intel Core i7-9700K")
               .producer("China")
               .build();
   }

   @Before
   public void init() {
       robotService = new RobotServiceImpl(robotDAO);
   }
Baris 1 - Runner kita. Baris 4 - kita ngisolasi layanan saka lapisan DAO kanthi ngganti mock. Baris 11 - kita nyetel entitas test (sing bakal digunakake minangka guinea pig) kanggo kelas. Baris 22 - kita nyetel obyek layanan, sing bakal dites.

@Test
public void updateTest() {
   when(robotDAO.findById(any(Long.class))).thenReturn(testRobot);
   when(robotDAO.update(any(Robot.class))).then(returnsFirstArg());
   Robot robotForUpdate = Robot
           .builder()
           .name("Vally")
           .cpu("AMD Ryzen 7 2700X")
           .build();

   Robot resultRobot = robotService.update(123L, robotForUpdate);

   assertNotNull(resultRobot);
   assertSame(resultRobot.getId(),testRobot.getId());
   assertThat(resultRobot.getName()).isEqualTo(robotForUpdate.getName());
   assertTrue(resultRobot.getCpu().equals(robotForUpdate.getCpu()));
   assertEquals(resultRobot.getProducer(),testRobot.getProducer());
}
Ing kene kita bisa ndeleng manawa tes kasebut duwe telung bagean sing jelas: Garis 3-9 - nemtokake peralatan. Baris 11 - nglakokake kode sing dites. Baris 13-17 - mriksa asil. Luwih rinci: Baris 3-4 - nyetel prilaku kanggo mock DAO. Baris 5 - nyetel conto sing bakal dianyari ing ndhuwur standar kita. Baris 11 - gunakake metode kasebut lan njupuk conto sing diasilake. Baris 13 - priksa manawa ora null. Baris 14 - mbandhingake ID asil lan argumen metode sing diwenehake. Baris 15 - priksa manawa jeneng kasebut dianyari. Baris 16 - ndeleng asil CPU. Baris 17 - kita ora nemtokake lapangan iki ing conto kasebut, mula kudu tetep padha. Kita mriksa kahanan kasebut ing kene. Ayo mbukak:Kabeh babagan pengujian unit: teknik, konsep, praktik - 6Tes iki ijo! Kita bisa ambegan lega :) Ing ringkesan, tes nambah kualitas kode lan nggawe proses pangembangan luwih fleksibel lan dipercaya. Mbayangno carane akeh gaweyan kanggo ngrancang piranti lunak nglibatno atusan file kelas. Nalika kita duwe tes unit sing ditulis kanggo kabeh kelas kasebut, kita bisa refactor kanthi yakin. Lan sing paling penting, mbantu kita nemokake bug sajrone pangembangan. Wong lanang lan wadon, mung iku sing dakkarepake dina iki. Ojo lali like, lan komen :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION