JavaRush /Java блогу /Random-KY /Java Unit Testing: техникалар, түшүнүктөр, практика
Константин
Деңгээл

Java Unit Testing: техникалар, түшүнүктөр, практика

Группада жарыяланган
Бүгүн сиз тесттер менен камтылбаган тиркемени таба албайсыз, андыктан бул тема башталгыч иштеп чыгуучулар үчүн болуп көрбөгөндөй актуалдуу болуп калат: тесттерсиз эч жакка жете албайсыз. Жарнама катары мурунку макалаларымды карап көрүүнү сунуштайм. Алардын айрымдары тесттерди камтыйт (жана ошондой болсо да макалалар абдан пайдалуу болот):
  1. MySql алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөө
  2. Көп тилдүү колдонууну ишке ашыруу
  3. Файлдарды тиркемеге жана алар жөнүндө маалыматтарды маалымат базасына сактоо
Келгиле, тестирлөөнүн кандай түрлөрү негизинен колдонулаарын карап көрөлү, андан кийин биз бирдиктүү тестирлөө жөнүндө бorшиңиз керек болгон нерселердин баарын майда-чүйдөсүнө чейин изилдеп чыгабыз.

Тесттин түрлөрү

сыноо деген эмне? Wiki айткандай: " Тест же тест бул системаны ар кандай кырдаалдарга жайгаштыруу жана андагы байкалуучу өзгөрүүлөргө көз салуу аркылуу системанын негизги процесстерин изилдөөнүн жолу." Башкача айтканда, бул белгилүү бир жагдайларда биздин системанын туура иштешин текшерүү. Бирдикти тестирлөө жөнүндө бардыгы: методдор, түшүнүктөр, практика - 2Келгиле, тесттин кандай түрлөрү бар экенин карап көрөлү:
  1. Бирдикти тестирлөө – бул системанын ар бир модулун өзүнчө сыноо болгон тесттер. Бул системанын минималдуу бөлүнүүчү бөлүктөрү болушу керек, мисалы, модулдар.

  2. Системалык тестирлөө - бул колдонмонун чоңураак бөлүгүнүн же бүтүндөй системанын иштешин текшерүү үчүн жогорку деңгээлдеги тест.

  3. Регрессиялык тестирлөө - жаңы функциялар же мүчүлүштүктөрдү оңдоолор колдонмонун учурдагы функционалдуулугуна таасир этеби же эски мүчүлүштүктөр кайра пайда болобу текшерүү үчүн колдонулган тест.

  4. Функционалдык тестирлөө - бул тиркеменин бир бөлүгүнүн спецификацияларда, колдонуучунун окуяларында ж.б. айтылган талаптарга шайкештигин текшерүү.

    Функционалдык тестирлөөнүн түрлөрү:

    • тутумдун ички ишке ашырылышын билүү менен өтүнмөнүн бир бөлүгүнүн талаптарга ылайык келүүсүнө “ак куту” тести ;
    • Системанын ички ишке ашырылышын билбестен, өтүнмөнүн бир бөлүгүнүн талаптарга ылайык келүүсүнө "кара куту" тести .
  5. Аткаруучулук тестирлөө - бул системанын же анын бир бөлүгүнүн белгилүү бир жүк астында иштөө ылдамдыгын аныктоо үчүн жазылган тесттердин бир түрү.
  6. Жүктөлгөн тестирлөө - стандарттык жүктөмдөрдүн астында системанын туруктуулугун текшерүү жана тиркеме туура иштеген максималдуу мүмкүн болгон чокусун табуу үчүн арналган тесттер.
  7. Стресс тестирлөө – стандарттуу эмес жүктөмдөрдүн астында тиркеменин иштешин текшерүү жана система кыйроого учурабай турган максималдуу мүмкүн болгон чокусун аныктоо үчүн арналган тестирлөөнүн бир түрү.
  8. Коопсуздук тести - системанын коопсуздугун текшерүү үчүн колдонулган тесттер (хакерлердин чабуулдарынан, вирустардан, жашыруун маалыматтарга уруксатсыз кирүүдөн жана жашоонун башка ырахаттарынан).
  9. Локалдаштыруу тести - бул колдонмо үчүн локалдаштыруу тести.
  10. Колдонуу жөндөмдүүлүгүн тестирлөө колдонуучулар үчүн колдонууга ыңгайлуулугун, түшүнүктүүлүгүн, жагымдуулугун жана үйрөнүүгө жөндөмдүүлүгүн текшерүүгө багытталган тестирлөөнүн бир түрү.
  11. Мунун баары жакшы угулат, бирок бул иш жүзүндө кантип иштейт? Бул жөнөкөй: Майк Кондун сыноо пирамидасы колдонулат: Бирдикти тестирлөө жөнүндө бардыгы: методдор, түшүнүктөр, практика - 4Бул пирамиданын жөнөкөйлөштүрүлгөн versionсы: азыр ал кичинекей бөлүктөргө бөлүнгөн. Бирок бүгүн биз бурмалап, эң жөнөкөй вариантты карап чыгабыз.
    1. Бирдик - тиркеменин ар кандай катмарларында колдонулган бирдик тесттери, тиркеменин эң кичине бөлүнүүчү логикасын текшерүү: мисалы, класс, бирок көбүнчө метод. Бул тесттер адатта тышкы логикадан мүмкүн болушунча обочолонтууга аракет кылат, башкача айтканда, тиркеменин калган бөлүгү стандарттык режимде иштеп жатат деген иллюзияны түзүүгө аракет кылат.

      Бул сыноолор ар дайым көп болушу керек (башка түрлөргө караганда), алар кичинекей бөлүктөрүн сынашат жана өтө жеңил, көп ресурстарды талап кылbyte (ресурстар менен мен RAM жана убакытты билдирет).

    2. Интеграция – интеграциялык тестирлөө. Ал системанын чоңураак бөлүктөрүн текшерет, башкача айтканда, бул логиканын бир нече бөлүктөрүнүн айкалышы (бир нече ыкмалар же класстар), же тышкы компонент менен иштөөнүн тууралыгы. Бул сыноолор бирдик сыноолоруна караганда азыраак болот, анткени алар оор.

      Интеграция тесттеринин мисалы катары, сиз маалымат базасына туташуу жана аны менен иштөө ыкмаларынын туура аткарылышын текшерүүнү карай аласыз .

    3. UI - колдонуучунун интерфейсинин иштешин текшерүүчү тесттер. Алар тиркеменин бардык деңгээлдеринде логикага таасир этет, ошондуктан аларды аягына чейин деп да аташат. Эреже катары, алардын саны азыраак, анткени алар эң оор жана эң керектүү (колдонулган) жолдорду текшериши керек.

      Жогорудагы сүрөттө биз үч бурчтуктун ар кандай бөлүктөрүнүн аянттарынын катышын көрөбүз: реалдуу иште бул сыноолордун санында болжол менен бирдей пропорция сакталат.

      Бүгүн биз эң көп колдонулган тесттерди - бирдик тесттерин кылдат карап чыгабыз, анткени бардык өзүн-өзү сыйлаган Java иштеп чыгуучулар аларды базалык деңгээлде колдоно алышы керек.

    Бирдикти сыноонун негизги түшүнүктөрү

    Сыноо камтуусу (Code Coverage) өтүнмө тестирлөөнүн сапатына негизги баа берүүнүн бири болуп саналат. Бул тесттер менен камтылган codeдун пайызы (0-100%). Практикада көп адамдар бул пайыздын артынан куушат, мен макул эмесмин, анткени алар керек эмес жерлерде тесттерди кошо башташат. Мисалы, биздин кызматта кошумча логикасы жок стандарттуу CRUD (түзүү/алуу/жаңыртуу/жок кылуу) операциялары бар. Бул ыкмалар репозиторий менен иштеген катмарга ишти тапшырган ортомчулар. Бул жагдайда, биз текшере турган эч нерсе жок: балким, бул ыкма дао ыкмасын чакырат, бирок бул олуттуу эмес. Сынактын камтылышын баалоо үчүн, адатта, кошумча куралдар колдонулат: JaCoCo, Cobertura, Clover, Эмма ж.б. Бул маселени кененирээк изилдөө үчүн, бир нече ылайыктуу макалаларды сактаңыз: TDD (Test-driven Development) - сыноого негизделген иштеп чыгуу. Бул ыкмада, биринчиден, белгилүү бир codeду текшере турган тест жазылат. Бул кара кутучаны текшерүү болуп чыкты: биз киргизүүдө эмне бар экенин билебиз жана чыгууда эмне болушу керектигин билебиз. Бул codeду кайталоодон сактайт. Сыноого негизделген иштеп чыгуу колдонмонун ар бир кичинекей функционалдуулугу үчүн тесттерди иштеп чыгуу жана иштеп чыгуу менен башталат. TDD мамилесинде, биринчиден, code эмне кыларын аныктаган жана текшерген тест иштелип чыгат. TDDнин негизги максаты - codeду ачык, жөнөкөй жана катасыз кылуу. Бирдикти тестирлөө жөнүндө бардыгы: методдор, түшүнүктөр, практика - 6Бул ыкма төмөнкү компоненттерден турат:
    1. Биз тестти жазып жатабыз.
    2. Биз тестти өткөрөбүз, ал өттүбү же жокпу (биз баары кызыл экенин көрүп жатабыз - коркпогула: ушундай болушу керек).
    3. Биз бул сыноону канааттандыра турган codeду кошобуз (тестти иштетиңиз).
    4. Биз codeду кайра түзөбүз.
    Бирдик тесттери тесттик автоматташтыруу пирамидасынын эң кичинекей элементтери экендигине таянып, TDD аларга негизделген. Бирдик тесттеринин жардамы менен биз каалаган класстын бизнес логикасын сынай алабыз. BDD (Behavior-driven Development) - жүрүм-турум аркылуу өнүктүрүү. Бул ыкма TDD негизделген. Тагыраак айтканда, иштеп чыгууга катышкан ар бир адам үчүн системанын жүрүм-турумун чагылдырган түшүнүктүү тилде (көбүнчө англис тorнде) жазылган мисалдарды колдонот. Биз бул терминди изилдебейбиз, анткени ал негизинен тестирлөөчүлөргө жана бизнес-аналитиктерге тиешелүү. Сыноо иши - сыналуучу codeдун аткарылышын текшерүү үчүн зарыл болгон кадамдарды, конкреттүү шарттарды жана параметрлерди сүрөттөгөн скрипт. Фикстура - бул текшерorп жаткан ыкманы ийгorктүү ишке ашыруу үчүн зарыл болгон тестирлөө чөйрөсүнүн абалы. Бул колдонулган шарттарда an objectтердин жана алардын жүрүм-турумунун алдын ала белгиленген жыйындысы.

    Сыноо этаптары

    Сыноо үч этаптан турат:
    1. Текшере турган маалыматтарды көрсөтүү (түзмөктөр).
    2. Сыноодогу codeду колдонуу (сыноодогу ыкманы чакыруу).
    3. Натыйжаларды текшерүү жана күтүлгөндөр менен салыштыруу.
    Бирдикти тестирлөө жөнүндө бардыгы: методдор, түшүнүктөр, практика - 7Сыноонун модулдуулугун камсыз кылуу үчүн сиз колдонмонун башка катмарларынан обочолонушуңуз керек. Бул шпалдар, шылдың жана шпиондор аркылуу жасалышы мүмкүн. Мазактар ​​- бул ыңгайлаштырылган an objectтер (мисалы, ар бир тестке мүнөздүү) жана биз алууну пландаштырган жооптор түрүндөгү ыкма чалууларына күтүүлөрдү коюуга мүмкүндүк берет. Күтүлгөн текшерүүлөр жасалма an objectтерге чалуу аркылуу ишке ашырылат. Stubs - тестирлөө учурунда чалууларга катуу жооп берет. Алар ошондой эле чалуу жөнүндө маалыматты сактай алат (мисалы, бул чалуулардын параметрлери же саны). Булар кээде өз термини менен аталат - шпион ( Spy ). Кээде бул терминдер чаташтырылып калат : айырмасы stub эч нерсени текшербейт, болгону берилген абалды окшоштурот . Мазак - бул күтүүлөр бар an object. Мисалы, берилген класстын ыкмасы белгилүү бир нече жолу чакырылышы керек. Башка сөз менен айтканда, сиздин тестиңиз такыр сынbyte, бирок шылдыңдан улам сынышы мүмкүн.

    Сыноо чөйрөлөрү

    Ошентип, эми бизнеске киришели. Java үчүн бир нече тестирлөө чөйрөлөрү (алHowтар) бар. Алардын эң популярдуусу JUnit жана TestNG. Биздин карап чыгуу үчүн биз колдонобуз: Бирдикти тестирлөө жөнүндө бардыгы: методдор, түшүнүктөр, практика - 8JUnit тести - бул класста камтылган метод, ал сыноо үчүн гана колдонулат. Класс, адатта, аягында +Тест менен сынап жаткан класс менен бирдей аталат. Мисалы, CarService→ CarServiceTest. Maven куруу системасы автоматтык түрдө мындай класстарды сыноо аймагына камтыйт. Чынында, бул класс тест классы деп аталат. Негизги annotationларды бир аз карап көрөлү: @Test - бул методдун сыноо ыкмасы катары аныктамасы (чындыгында, бул annotation менен белгиленген ыкма бирдик тести). @Before - ар бир сыноонун алдында аткарыла турган ыкманы белгилейт. Мисалы, класстын тест маалыматтарын толтуруу, киргизилген маалыматтарды окуу ж.б. @After - ар бир сыноодон кийин чакырыла турган ыкманын үстүнө жайгаштырылган (маалыматтарды тазалоо, демейки маанилерди калыбына келтирүү). @BeforeClass - методдун үстүнө жайгаштырылган - @Before окшош. Бирок бул ыкма берилген класс үчүн бардык сыноолордун алдында бир гана жолу чакырылат жана ошондуктан статикалык болушу керек. Бул тест базасын көтөрүү сыяктуу оор операцияларды аткаруу үчүн колдонулат. @AfterClass @BeforeClass карама-каршы: берилген класс үчүн бир жолу аткарылган, бирок бардык сыноолордон кийин аткарылган. Мисалы, туруктуу ресурстарды тазалоо же маалымат базасынан ажыратуу үчүн колдонулат. @Ignore - төмөндөгү ыкма өчүрүлгөндүгүн жана жалпы тесттерди жүргүзүүдө көңүл бурулбай турганын белгилейт. Ал ар кандай учурларда колдонулат, мисалы, эгерде базалык ыкма өзгөртүлгөн болсо жана ал үчүн тестти кайра жасоого убакыт жок болсо. Мындай учурларда, ошондой эле сүрөттөмө кошуу сунушталат - @Ignore("Кээ бир сүрөттөмө"). @Test (күтүлгөн = Exception.class) - терс тесттер үчүн колдонулат. Бул ката болгон учурда методдун кандайча иш алып барарын текшерген тесттер, башкача айтканда, тест методдун кандайдыр бир өзгөчөлүктү таштоосун күтөт. Мындай ыкма @Test annotationсы менен белгиленет, бирок ката менен кармалат. @Test(timeout=100) - методдун 100 миллисекунддан ашпаган убакытта аткарылышын текшерет. @Mock - класс берилген an objectти шылдың катары коюу үчүн талаада колдонулат (бул Junit китепканасынан эмес, Mockitoдон) жана эгер бизге керек болсо, биз шылдың жүрүм-турумун белгилүү бир кырдаалда орнотобуз , түздөн-түз сыноо ыкмасы. @RunWith(MockitoJUnitRunner.class) - метод класстын үстүнө жайгаштырылган. Бул андагы тесттерди жүргүзүү үчүн баскыч. Жөө күлүктөр ар кандай болушу мүмкүн: мисалы, төмөнкүлөр бар: MockitoJUnitRunner, JUnitPlatform, SpringRunner, ж.б.). JUnit 5те @RunWith annotationсы күчтүүрөөк @ExtendWith annotationсына алмаштырылган. Келгиле, натыйжаларды салыштыруунун кээ бир ыкмаларын карап көрөлү:
    • assertEquals(Object expecteds, Object actuals)— берилүүчү an objectилердин бирдей экендигин текшерет.
    • assertTrue(boolean flag)— берилген маани чындыкка кайтарылганын текшерет.
    • assertFalse(boolean flag)— берилген маани жалган экенин текшерет.
    • assertNull(Object object)– an objectтин нөл экенин текшерет.
    • assertSame(Object firstObject, Object secondObject)— өткөн баалуулуктар бир эле an objectке тиешелүү экендигин текшерет.
    • assertThat(T t, Matcher<T> matcher)— t дал келүүчүдө көрсөтүлгөн шартты канааттандырарын текшерет.
    Assertjден пайдалуу салыштыруу формасы да бар - assertThat(firstObject).isEqualTo(secondObject) Бул жерде мен негизги ыкмалар жөнүндө айттым, анткени калгандары жогоруда айтылгандардын ар кандай варианттары.

    Сыноо практикасы

    Эми жогорудагы материалды конкреттүү мисал менен карап көрөлү. Кызмат үчүн ыкманы сынап көрөбүз - жаңыртуу. Дао катмарын эске албайбыз, анткени ал биздин демейки. Тесттер үчүн баштоону кошолу:
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <version>2.2.2.RELEASE</version>
       <scope>test</scope>
    </dependency>
    Ошентип, кызмат классы:
    @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 - жаңыланган an objectти маалымат базасынан тартыңыз 9-14 - an objectти куруучу аркылуу түзүңүз, эгер кирген an objectте талаа бар болсо - аны орнотуңуз, эгерде жок болсо - базада эмне бар экенин калтырыңыз жана биздин тестти караңыз:
    @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 — биздин Runner 4 — шылуундун ордуна кызматты дао катмарынан обочолонтуу
    @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());
    }
    Бул жерде биз тесттин үч бөлүккө так бөлүнүшүн көрөбүз: 3-9 - орнотууларды орнотуу 11 - сыналган бөлүктү аткаруу 13-17 - натыйжаларды текшерүү Көбүрөөк маалымат: 3-4 - мока дао үчүн жүрүм-турумду орнотуу 5 - инстанцияны орнотуу стандартыбыздын үстүнө жаңыртабыз деп 11 - ыкманы колдонуңуз жана натыйжада мисалды алыңыз 13 - нөл эмес экенин текшериңиз 14 - натыйжанын идентификаторун жана көрсөтүлгөн ыкманын аргументтерин текшериңиз 15 - аталыштын жаңыланганын текшериңиз 16 - карап көрүңүз натыйжада cpu 17 - биз муну жаңыртуу инстанциясы талаасында орнотпогондуктан, ал ошол эле бойдон калышы керек, аны текшерип көрөлү. Бирдикти тестирлөө жөнүндө бардыгы: методдор, түшүнүктөр, практика - 9Келгиле, ишке киргизели: Бирдикти тестирлөө жөнүндө бардыгы: ыкмалар, түшүнүктөр, практика - 10Тест жашыл, сиз дем чыгара аласыз)) Ошентип, кыскача айталы: тестирлөө codeдун сапатын жакшыртат жана иштеп чыгуу процессин ийкемдүү жана ишенимдүү кылат. Жүздөгөн класстык файлдар менен программалык камсыздоону кайра иштеп чыгууда канча күч жумшашыбыз керектигин элестетиңиз. Бардык бул класстар үчүн бирдик тесттери жазылгандан кийин, биз ишенимдүү түрдө рефакторлорду жасай алабыз. Эң негизгиси, бул иштеп чыгуу учурунда каталарды оңой табууга жардам берет. Балдар, бүгүн мен үчүн баары: лайк басып, комментарий жазгыла))) Бирдикти тестирлөө жөнүндө бардыгы: методдор, түшүнүктөр, практика - 11
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION