JavaRush /Blog Java /Random-MS /Ujian Unit Java: teknik, konsep, amalan

Ujian Unit Java: teknik, konsep, amalan

Diterbitkan dalam kumpulan
Hari ini anda hampir tidak akan menemui aplikasi yang tidak diliputi dengan ujian, jadi topik ini akan menjadi lebih relevan berbanding sebelum ini untuk pembangun pemula: tanpa ujian anda tidak boleh sampai ke mana-mana. Sebagai iklan, saya cadangkan anda melihat artikel saya yang lepas. Sebahagian daripada mereka meliputi ujian (dan walaupun begitu artikel akan sangat berguna):
  1. Ujian integrasi pangkalan data menggunakan MariaDB untuk menggantikan MySql
  2. Pelaksanaan aplikasi berbilang bahasa
  3. Menyimpan fail ke aplikasi dan data tentangnya ke pangkalan data
Mari pertimbangkan jenis ujian yang digunakan pada dasarnya, dan selepas itu kami akan mengkaji secara terperinci semua yang anda perlu ketahui tentang ujian unit.

Jenis-jenis ujian

Apakah ujian? Seperti yang dikatakan Wiki: " Ujian atau ujian ialah satu cara untuk mengkaji proses asas sistem dengan meletakkan sistem dalam situasi yang berbeza dan menjejaki perubahan yang boleh diperhatikan di dalamnya." Dalam erti kata lain, ini adalah ujian operasi yang betul sistem kami dalam situasi tertentu. Semua tentang ujian Unit: kaedah, konsep, amalan - 2Baiklah, mari kita lihat jenis ujian yang ada:
  1. Ujian unit ialah ujian yang tugasnya adalah untuk menguji setiap modul sistem secara individu. Adalah wajar bahawa ini menjadi kepingan sistem yang boleh dibahagikan secara minimum, sebagai contoh, modul.

  2. Ujian sistem ialah ujian peringkat tinggi untuk menguji operasi sekeping aplikasi yang lebih besar atau sistem secara keseluruhan.

  3. Ujian regresi ialah ujian yang digunakan untuk menyemak sama ada ciri baharu atau pembetulan pepijat mempengaruhi fungsi sedia ada aplikasi dan sama ada pepijat lama muncul semula.

  4. Ujian fungsional adalah menyemak pematuhan sebahagian aplikasi dengan keperluan yang dinyatakan dalam spesifikasi, cerita pengguna, dsb.

    Jenis ujian fungsi:

    • ujian "kotak putih" untuk pematuhan sebahagian daripada aplikasi dengan keperluan dengan pengetahuan tentang pelaksanaan dalaman sistem;
    • Ujian "kotak hitam" untuk pematuhan sebahagian daripada aplikasi dengan keperluan tanpa pengetahuan tentang pelaksanaan dalaman sistem.
  5. Ujian prestasi ialah sejenis ujian yang ditulis untuk menentukan kelajuan sistem atau sebahagian daripadanya berjalan di bawah beban tertentu.
  6. Ujian beban - ujian yang direka untuk memeriksa kestabilan sistem di bawah beban standard dan untuk mencari puncak maksimum yang mungkin di mana aplikasi berfungsi dengan betul.
  7. Ujian tekanan ialah sejenis ujian yang direka untuk menyemak kefungsian aplikasi di bawah beban bukan standard dan untuk menentukan puncak maksimum yang mungkin di mana sistem tidak akan ranap.
  8. Ujian keselamatan - ujian yang digunakan untuk memeriksa keselamatan sistem (daripada serangan penggodam, virus, akses tanpa kebenaran kepada data sulit dan kegembiraan hidup yang lain).
  9. Ujian penyetempatan ialah ujian penyetempatan untuk aplikasi.
  10. Ujian kebolehgunaan ialah sejenis ujian yang bertujuan untuk menyemak kebolehgunaan, kebolehfahaman, daya tarikan dan kebolehpelajaran untuk pengguna.
  11. Ini semua kedengaran bagus, tetapi bagaimana ia berfungsi dalam amalan? Ia mudah: Piramid ujian Mike Cohn digunakan: Semua tentang ujian Unit: teknik, konsep, amalan - 4Ini adalah versi ringkas piramid: kini ia dibahagikan kepada bahagian yang lebih kecil. Tetapi hari ini kita tidak akan menyeleweng dan mempertimbangkan pilihan yang paling mudah.
    1. Unit - ujian unit yang digunakan dalam pelbagai lapisan aplikasi, menguji logik boleh bahagi terkecil aplikasi: contohnya, kelas, tetapi selalunya kaedah. Ujian ini biasanya cuba mengasingkan sebanyak mungkin daripada logik luaran, iaitu, untuk mencipta ilusi bahawa seluruh aplikasi berfungsi dalam mod standard.

      Selalunya terdapat banyak ujian ini (lebih daripada jenis lain), kerana ia menguji kepingan kecil dan sangat ringan, tidak memakan banyak sumber (dengan sumber yang saya maksudkan RAM dan masa).

    2. Integrasi - ujian integrasi. Ia menyemak bahagian sistem yang lebih besar, iaitu, ia sama ada gabungan beberapa keping logik (beberapa kaedah atau kelas), atau ketepatan bekerja dengan komponen luaran. Biasanya terdapat lebih sedikit ujian ini daripada ujian Unit, kerana ia lebih berat.

      Sebagai contoh ujian penyepaduan, anda boleh mempertimbangkan untuk menyambung ke pangkalan data dan menyemak sama ada kaedah yang berfungsi dengannya berfungsi dengan betul .

    3. UI - ujian yang menyemak operasi antara muka pengguna. Mereka mempengaruhi logik pada semua peringkat aplikasi, itulah sebabnya mereka juga dipanggil hujung-ke-hujung. Sebagai peraturan, terdapat lebih sedikit daripada mereka, kerana mereka adalah yang paling berat dan mesti menyemak laluan yang paling diperlukan (terpakai).

      Dalam rajah di atas kita melihat nisbah kawasan bahagian yang berlainan bagi segi tiga: kira-kira perkadaran yang sama dikekalkan dalam bilangan ujian ini dalam kerja sebenar.

      Hari ini kita akan melihat lebih dekat pada ujian yang paling banyak digunakan - ujian unit, kerana semua pembangun Java yang menghormati diri seharusnya boleh menggunakannya pada tahap asas.

    Konsep utama ujian unit

    Liputan ujian (Liputan Kod) adalah salah satu penilaian utama kualiti ujian aplikasi. Ini ialah peratusan kod yang diliputi oleh ujian (0-100%). Dalam amalan, ramai orang mengejar peratusan ini, yang saya tidak bersetuju, kerana mereka mula menambah ujian di mana mereka tidak diperlukan. Sebagai contoh, perkhidmatan kami mempunyai operasi CRUD (buat/dapatkan/kemas kini/padam) standard tanpa logik tambahan. Kaedah ini adalah perantara semata-mata yang mewakilkan kerja kepada lapisan yang berfungsi dengan repositori. Dalam keadaan ini, kita tidak mempunyai apa-apa untuk diuji: mungkin sama ada kaedah ini memanggil kaedah daripada Tao, tetapi ini tidak serius. Untuk menilai liputan ujian, alat tambahan biasanya digunakan: JaCoCo, Cobertura, Clover, Emma, ​​​​dsb. Untuk kajian yang lebih terperinci tentang isu ini, simpan beberapa artikel yang sesuai: TDD (Pembangunan dipacu ujian) - pembangunan dipacu ujian. Dalam pendekatan ini, pertama sekali, ujian ditulis yang akan menyemak kod tertentu. Ternyata ujian kotak hitam: kita tahu apa yang ada pada input dan kita tahu apa yang harus berlaku pada output. Ini mengelakkan pertindihan kod. Pembangunan dipacu ujian bermula dengan mereka bentuk dan membangunkan ujian untuk setiap fungsi kecil aplikasi. Dalam pendekatan TDD, pertama, satu ujian dibangunkan yang mentakrifkan dan mengesahkan perkara yang akan dilakukan oleh kod tersebut. Matlamat utama TDD adalah untuk menjadikan kod lebih jelas, mudah dan bebas ralat. Semua tentang ujian Unit: kaedah, konsep, amalan - 6Pendekatan terdiri daripada komponen berikut:
    1. Kami sedang menulis ujian kami.
    2. Kami menjalankan ujian, sama ada lulus atau tidak (kami melihat bahawa semuanya berwarna merah - jangan gentar: beginilah sepatutnya).
    3. Kami menambah kod yang sepatutnya memenuhi ujian ini (jalankan ujian).
    4. Kami memfaktorkan semula kod.
    Berdasarkan fakta bahawa ujian unit adalah elemen terkecil dalam piramid automasi ujian, TDD berdasarkannya. Dengan bantuan ujian unit, kami boleh menguji logik perniagaan mana-mana kelas. BDD (Pembangunan yang didorong oleh tingkah laku) - pembangunan melalui tingkah laku. Pendekatan ini adalah berdasarkan TDD. Secara lebih khusus, ia menggunakan contoh yang ditulis dalam bahasa yang jelas (biasanya dalam bahasa Inggeris) yang menggambarkan tingkah laku sistem untuk semua orang yang terlibat dalam pembangunan. Kami tidak akan mendalami istilah ini, kerana ia memberi kesan terutamanya kepada penguji dan penganalisis perniagaan. Kes Ujian - skrip yang menerangkan langkah, syarat khusus dan parameter yang diperlukan untuk mengesahkan pelaksanaan kod yang sedang diuji. Lekapan ialah keadaan persekitaran ujian yang diperlukan untuk menjayakan pelaksanaan kaedah yang diuji. Ini ialah set objek yang telah ditetapkan dan kelakuannya di bawah keadaan yang digunakan.

    Peringkat ujian

    Ujian ini terdiri daripada tiga peringkat:
    1. Menentukan data yang akan diuji (lekapan).
    2. Menggunakan kod di bawah ujian (memanggil kaedah di bawah ujian).
    3. Menyemak keputusan dan membandingkannya dengan yang diharapkan.
    Semua tentang ujian Unit: kaedah, konsep, amalan - 7Untuk memastikan modulariti ujian, anda perlu diasingkan daripada lapisan lain aplikasi. Ini boleh dilakukan menggunakan stub, ejekan dan pengintip. Olok-olok ialah objek yang boleh disesuaikan (contohnya, khusus untuk setiap ujian) dan membolehkan anda menetapkan jangkaan untuk panggilan kaedah dalam bentuk respons yang kami rancang untuk terima. Pemeriksaan jangkaan dilakukan melalui panggilan ke objek Mock. Stub - memberikan respons berwayar keras kepada panggilan semasa ujian. Mereka juga boleh menyimpan maklumat tentang panggilan (contohnya, parameter atau bilangan panggilan ini). Ini kadangkala dipanggil dengan istilah mereka sendiri - spy ( Spy ). Kadangkala istilah rintisan dan olok-olok ini keliru: perbezaannya ialah rintisan tidak memeriksa apa-apa, tetapi hanya mensimulasikan keadaan tertentu. Olok-olok ialah objek yang mempunyai jangkaan. Sebagai contoh, kaedah kelas tertentu mesti dipanggil beberapa kali. Dalam erti kata lain, ujian anda tidak akan putus kerana rintisan, tetapi ia mungkin rosak kerana ejekan.

    Persekitaran ujian

    Jadi sekarang mari kita turun ke perniagaan. Terdapat beberapa persekitaran ujian (rangka kerja) tersedia untuk Java. Yang paling popular ialah JUnit dan TestNG. Untuk semakan kami, kami menggunakan: Semua tentang ujian Unit: kaedah, konsep, amalan - 8Ujian JUnit ialah kaedah yang terkandung dalam kelas yang digunakan hanya untuk ujian. Kelas biasanya dinamakan sama dengan kelas yang diuji dengan +Ujian pada penghujungnya. Contohnya, CarService→ CarServiceTest. Sistem binaan Maven secara automatik menyertakan kelas sedemikian dalam kawasan ujian. Malah, kelas ini dipanggil kelas ujian. Mari kita lihat sedikit anotasi asas: @Test - definisi kaedah ini sebagai kaedah ujian (sebenarnya, kaedah yang ditandakan dengan anotasi ini ialah ujian unit). @Sebelum - menandakan kaedah yang akan dilaksanakan sebelum setiap ujian. Contohnya, mengisi data ujian kelas, membaca data input, dsb. @Selepas - diletakkan di atas kaedah yang akan dipanggil selepas setiap ujian (membersihkan data, memulihkan nilai lalai). @BeforeClass - diletakkan di atas kaedah - sama dengan @Before. Tetapi kaedah ini dipanggil sekali sahaja sebelum semua ujian untuk kelas tertentu dan oleh itu mestilah statik. Ia digunakan untuk melakukan lebih banyak operasi tugas berat, seperti mengangkat pangkalan data ujian. @AfterClass adalah bertentangan dengan @BeforeClass: dilaksanakan sekali untuk kelas tertentu, tetapi dilaksanakan selepas semua ujian. Digunakan, sebagai contoh, untuk membersihkan sumber yang berterusan atau memutuskan sambungan daripada pangkalan data. @Ignore - ambil perhatian bahawa kaedah di bawah dilumpuhkan dan akan diabaikan apabila menjalankan ujian secara keseluruhan. Ia digunakan dalam kes yang berbeza, contohnya, jika kaedah asas telah diubah dan tidak ada masa untuk membuat semula ujian untuknya. Dalam kes sedemikian, ia juga dinasihatkan untuk menambah penerangan - @Ignore("Some description"). @Test (dijangka = Exception.class) - digunakan untuk ujian negatif. Ini adalah ujian yang menyemak cara sesuatu kaedah bertindak sekiranya berlaku ralat, iaitu, ujian menjangkakan kaedah itu akan mengeluarkan beberapa pengecualian. Kaedah sedemikian dilambangkan dengan anotasi @Test, tetapi dengan ralat untuk ditangkap. @Test(timeout=100) - menyemak sama ada kaedah dilaksanakan dalam masa tidak lebih daripada 100 milisaat. @Mock - kelas digunakan di atas medan untuk menetapkan objek yang diberikan sebagai olok-olok (ini bukan dari perpustakaan Junit, tetapi dari Mockito), dan jika kita memerlukannya, kita akan menetapkan tingkah laku olok-olok dalam situasi tertentu , secara langsung dalam kaedah ujian. @RunWith(MockitoJUnitRunner.class) - kaedah diletakkan di atas kelas. Ini adalah butang untuk menjalankan ujian di dalamnya. Pelari boleh berbeza: contohnya, terdapat yang berikut: MockitoJUnitRunner, JUnitPlatform, SpringRunner, dll.). Dalam JUnit 5, anotasi @RunWith telah digantikan dengan anotasi @ExtendWith yang lebih berkuasa. Mari kita lihat beberapa kaedah untuk membandingkan hasil:
    • assertEquals(Object expecteds, Object actuals)— menyemak sama ada objek yang dihantar adalah sama.
    • assertTrue(boolean flag)— menyemak sama ada nilai yang diluluskan kembali benar.
    • assertFalse(boolean flag)— menyemak sama ada nilai yang diluluskan mengembalikan palsu.
    • assertNull(Object object)– menyemak sama ada objek itu batal.
    • assertSame(Object firstObject, Object secondObject)— menyemak sama ada nilai yang diluluskan merujuk kepada objek yang sama.
    • assertThat(T t, Matcher<T> matcher)— menyemak sama ada t memenuhi syarat yang dinyatakan dalam pemadanan.
    Terdapat juga bentuk perbandingan yang berguna dari assertj - assertThat(firstObject).isEqualTo(secondObject) Di sini saya bercakap tentang kaedah asas, kerana selebihnya adalah variasi yang berbeza di atas.

    Latihan ujian

    Sekarang mari kita lihat bahan di atas menggunakan contoh khusus. Kami akan menguji kaedah untuk perkhidmatan - kemas kini. Kami tidak akan mempertimbangkan lapisan dao, kerana ia adalah lalai kami. Mari tambahkan permulaan untuk ujian:
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <version>2.2.2.RELEASE</version>
       <scope>test</scope>
    </dependency>
    Jadi, kelas perkhidmatan:
    @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());
       }
    }
    8 - tarik objek yang dikemas kini dari pangkalan data 9-14 - buat objek melalui pembina, jika objek masuk mempunyai medan - tetapkannya, jika tidak - tinggalkan apa yang ada dalam pangkalan data Dan lihat ujian kami:
    @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);
       }
    1 — Pelari 4 kami — asingkan perkhidmatan daripada lapisan dao dengan menggantikan olok-olok 11 — tetapkan entiti ujian untuk kelas (yang akan kami gunakan sebagai hamster ujian) 22 — tetapkan objek perkhidmatan yang akan kami uji
    @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());
    }
    Di sini kita melihat pembahagian ujian yang jelas kepada tiga bahagian: 3-9 - menetapkan lekapan 11 - melaksanakan bahagian yang diuji 13-17 - menyemak keputusan Butiran lanjut: 3-4 - menetapkan tingkah laku untuk moka dao 5 - tetapan contoh yang akan kami kemas kini di atas standard 11 kami - gunakan kaedah dan ambil contoh yang terhasil 13 - semak bahawa ia bukan sifar 14 - semak ID hasil dan hujah kaedah yang ditentukan 15 - semak sama ada nama telah dikemas kini 16 - lihat keputusan oleh cpu 17 - memandangkan kami tidak menetapkan ini dalam medan contoh kemas kini, ia sepatutnya kekal sama, mari semaknya. Semua tentang ujian Unit: kaedah, konsep, amalan - 9Mari kita lancarkan: Semua tentang ujian Unit: teknik, konsep, amalan - 10Ujian berwarna hijau, anda boleh menghembus nafas)) Jadi, mari kita ringkaskan: ujian meningkatkan kualiti kod dan menjadikan proses pembangunan lebih fleksibel dan boleh dipercayai. Bayangkan berapa banyak usaha yang perlu kita belanjakan apabila mereka bentuk semula perisian dengan beratus-ratus fail kelas. Sebaik sahaja kami mempunyai ujian unit yang ditulis untuk semua kelas ini, kami boleh memfaktorkan semula dengan yakin. Dan yang paling penting, ia membantu kami mencari ralat dengan mudah semasa pembangunan. Lelaki, itu sahaja untuk saya hari ini: tuangkan suka, tulis komen))) Semua tentang ujian Unit: kaedah, konsep, amalan - 11
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION