ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 125
Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 85
Abonament PDF

JUnit 5 - o nouă abordare, noi funcționalităţi

Cătălin Tudose
Java and Web Technologies Expert @ Luxoft Training
PROGRAMARE

JUnit este un framework de testare pentru limbajul de programare Java. Versiunea JUnit 5 a fost reproiectată să rezolve anumite probleme particulare ale precedentelor versiuni. De asemenea, oferă o nouă arhitectură, cu posibilitatea de a crea a ierarhie de teste, cu assertions şi assumptions, cu teste dinamice şi parametrizate. Acest articol este o scurtă introducere în JUnit 5, pentru a pune la dispoziţie cititorului, posibilitatea de a înţelege noua arhitectură şi noile funcţionalităţi pe care să le exploreze mai departe.

JUnit, ca framework de testare unitară pentru limbajul de programare Java, este o unealtă foarte importantă pentru abordarea test-driven development (dezvoltare ghidată de teste). Este parte a unei familii de frameworkuri de testare, numite colectiv xUnit.
JUnit este legat la compilare ca și JAR, fiind cel mai frecvent inclusă bibliotecă externă în proiectele Java.

TDD (Test Driven Development) este un proces de dezvoltare software care se bazează pe repetarea unui scurt ciclu: mai întâi, cerinţele sunt transformate în test-case-uri specifice; apoi, software-ul este îmbunătăţit doar să treacă noile teste. Acest lucru este diferit de dezvoltarea care permite software-ului să fie creat fără a dovedi că îndeplineşte cerinţele.

Beneficiile TDD includ:

Programatorul este ghidat de ţinte clare.

Neajunsurile JUnit 4

JUnit 4 apărut în 2006, pune la dispoziţie o arhitectură simplă şi monolitică. Întreaga funcţionalitate este concentrată într-un singur fişier JAR. În ciuda aparentei sale simplităţi, au apărut o serie de probleme, care s-au agravat pe măsura trecerii timpului.

Faptul că API-ul existent nu este flexibil a forţat IDE-urile şi uneltele care utilizau JUnit să fie puternic cuplate cu acesta. Era nevoie să se acceseze implementarea internă a JUnit sau chiar să se utilizeze reflexia pentru a obţine informaţia dorită.

Aşadar, de vreme ce acelaşi fişier JAR era utilizat de toată lumea şi IDE-urile erau puternic cuplate cu acesta, posibilităţile de evoluţie ale JUnit erau serios reduse. Schimbarea unei variabile sau a unei metode private putea să îi afecteze pe cei care o utilizau din exterior. Un nou API proiectat pentru astfel de unelte, şi o nouă arhitectură erau necesare pentru a asigura evoluţia ulterioară.

Noua abordare modulară

O nouă abordare, una modulară, era necesară pentru a permite evoluţia JUnit. Separarea logică solicită:

În consecinţă, arhitectura JUnit 5 rezultată conţine trei module:

JUnit Platform, care serveşte pentru lansarea frameworkului de testare pe maşina virtuală Java. De asemenea, oferă un API pentru lansarea testelor de la consolă, din IDE-uri sau din alte unelte.

JUnit Jupiter este o combinaţie între noul model de programare şi modelul de extensie pentru scrierea testelor şi a extensiilor în JUnit 5. Numele a fost ales de la a cincea planetă a sistemului solar, care este şi cea mai mare.

JUnit Vintage oferă un motor de testare pentru a rula teste JUnit 3 şi JUnit 4 pe noua platformă, asigurând şi necesara compatibilitate înapoi.

Pasul spre JUnit 5

Pentru a putea utiliza JUnit 5 într-un proiect Java, următoarele dependenţe trebuie adăugate la configuraţia Maven:

<dependencies>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.0.1</version>
  </dependency>

  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.0.1</version>
  </dependency>

  <dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-runner</artifactId>
    <version>1.0.1</version>
  </dependency>
</dependencies>

Următoarele diferenţe importante există între JUnit 4 şi JUnit 5:

Arhitectură

Versiuni de Java necesare pentru rulare

Adnotări

Primul test JUnit 5

Spre deosebire de JUnit 4, clasa de test şi metodele de test pot fi package private. Un test simplu arată astfel:

class TestFixturesExample {
  private static 
   HeavyResourceRequiredForAllTests heavyResource;

  private TestSetup testSetup;
  private SystemUnderTest systemUnderTest;

  @BeforeAll
  static void willBeDoneBeforeAllTests() {
    System.out.println("@BeforeAll");
    heavyResource = 
      new HeavyResourceRequiredForAllTests(
      "@BeforeAll", "@AfterAll");

    heavyResource.start(new DummyConfiguration());
  }

 @AfterAll
  static void willBeDoneAfterAllTests() {
    heavyResource.close();
  }
  @BeforeEach
  void willBeDoneBeforeEachTest() {
  testSetup = new TestSetup(
    "@BeforeEach", "@AfterEach");

    testSetup.prepare();
    systemUnderTest = new SystemUnderTest();
  }

  @AfterEach
  void willBeDoneAfterEachTest() {
    testSetup.cleanUp();
  }

  @Test
  void shouldReturnTheTruth() {
  Fact result = systemUnderTest.returnTheTruth();

    assertTrue(result.isTruth());
  }

  @Test
  void shouldReturnTheLie() {
   Fact result = systemUnderTest.returnTheLie();

   assertFalse(result.isTruth());
  }
}

Câteva remarci despre testul de mai sus:

  1. Metoda adnotată cu @BeforeAll va fi executată o singură dată, înaintea rulării testelor.

  2. Metoda adnotată cu @BeforeEach va fi executată de fiecare dată, înaintea execuţiei fiecărui test.

  3. Metodele adnotate cu @Test vor fi executate una câte una, pentru verificarea funcţionalităţii.

  4. Metoda adnotată cu @AfterEach va fi executată de fiecare dată după rularea unui test.

  5. Metoda adnotată cu @AfterAll va fi executată o singură data, după rularea tuturor testelor.

Assertions în JUnit 5

JUnit Jupiter pune la dispoziţie mai multe metode de tip assertion decât JUnit 4. Au fost adăugate câteva care funcţionează foarte bine împreună cu expresiile lambda din Java 8. Toate metodele de acest fel din JUnit Jupiter sunt statice şi provin din clasa org.junit.jupiter.api.Assertions.

Comparaţia între assertions în JUnit 4 şi JUnit 5 arată astfel:

Assertions

Mesajul din assertions este ultimul parametru al metodelor:

static void assertX(..., String message)
static void assertX(..., Supplier  messageSupplier)

Supplierul permite iniţializarea leneşă în cazul mesajelor complexe. O bucată de cod care să utilizeze posibile assertions arată astfel:

class AssertionsExample {
  private final SystemUnderTest systemUnderTest = 
    new SystemUnderTest("Assertions");

  @Test
  void shouldRecognizeWhenTestsStarted() {
    systemUnderTest.examine();
    assertTrue(systemUnderTest.isUnderTest());
  }

  @Test
  void shouldRecognizeIfTestsDidNotStarted() {
    assertFalse(systemUnderTest.isUnderTest());
  }

  @Test
  void shouldReturnNullInCaseOfNoJob() {
    assertNull(systemUnderTest.getCurrentJob());
  }

  @Test
  void shouldReturnJobIfThereIsOneRun() {
    systemUnderTest.addJob(aSomeJob());
    systemUnderTest.run();
    assertNotNull(systemUnderTest.getCurrentJob());
  }

  @Test
  void shouldRecognizeTheSameJob() {
    Job job = aSomeJob();
    systemUnderTest.addJob(job);
    systemUnderTest.run();
    assertSame(job, systemUnderTest.getCurrentJob());
  }

  @Test
  void shouldRecognizeNotTheSameJob() {
    systemUnderTest.addJob(aSomeJob());
    systemUnderTest.run();
    assertNotSame(aSomeJob(),  
      systemUnderTest.getCurrentJob());
  }

  @Test
  void shouldRecognizeEqualJob() {
    systemUnderTest.addJob(aSomeJob());
    systemUnderTest.run();
    assertEquals(aSomeJob(), 
      systemUnderTest.getCurrentJob());
  }

  @Test
  void shouldRecognizeNotEqualJob() {
    systemUnderTest.addJob(aSomeJob());
    systemUnderTest.run();
    assertNotEquals(aDifferentJob(), 
      systemUnderTest.getCurrentJob());
    }

  @Test
  void shouldRecognizeEqualJobs() {
  Object[] expectedJobs = 
    {aSomeJob(), aDifferentJob()};

    systemUnderTest.addJob(aSomeJob());
    systemUnderTest.addJob(aDifferentJob());
    assertArrayEquals(expectedJobs, 
      systemUnderTest.getJobs());
  }

  private Job aDifferentJob() {
    return aJob("different job");
  }

  private Job aSomeJob() {
    return aJob("some job");
  }

  private Job aJob(String name) {
    return new Job(name);
  }
}

Assumptions în JUnit 5

JUnit Jupiter pune la dispoziţie o parte din metodele de tip assumption din JUnit 4. JUnit Jupiter adaugă de asemenea, metode care funcţionează împreună cu expresiile lambda Java 8. Toate metodele de tip assumption din JUnit Jupiter sunt statice şi provin din clasa org.junit.jupiter.api.Assumptions. Parametrul mesaj este pe ultima poziţie.

Metodele de tip assertions sunt executate doar în cazul în care presupunerile de tip assumption sunt îndeplinite.

Metoda arată astfel:

static void assumingThat(
  BooleanSupplier assumptionSupplier, 
  Executable executable)

O comparaţie între assumptions în JUnit 4 şi JUnit 5 se prezintă în această formă:

Assumptions

Utilizarea unei metode de tip assume poate arăta așa:

class AssumeExample {
  private static final String 
    EXPECTED_JAVA_VERSION = "1.8";

  private final TestsEnvironment 
    environment = new TestsEnvironment(
      new JavaSpecification(
        System.getProperty(
        "java.vm.specification.version")),
      new OperationSystem(
        System.getProperty(
        "os.name"), System.getProperty("os.arch"))
  );

  private final SystemUnderTest 
    systemUnderTest = new SystemUnderTest();

  @BeforeEach
  void init() {
    assumeTrue(environment.isWindows());
  }

  @Test
  void shouldRecognizeThatHasNoJobToRun() {
    assumingThat(
      () -> environment.aJavaVersion()
        .equals(EXPECTED_JAVA_VERSION),
        () -> assertFalse(
        systemUnderTest.hasJobToRun()));
  }

  @Test
  void shouldRecognizeThatHasJobToRun() {
   assumeTrue(environment.isAmd64Architecture());
   systemUnderTest.run(new Job());
   assertTrue(systemUnderTest.hasJobToRun());
  }
}

Concluzii

JUnit 5 oferă un API nou şi flexibil pentru scrierea de teste, pentru assertions şi assumptions. Sunt acordate o mulţime de metode statice şi adaptate noilor facilităţi de programare funcţională, introduse de Java 8. De asemenea, noua arhitectură modulară facilitează atât munca dezvoltatorului cât şi interacţiunea cu IDE-urile şi cu alte unelte. Cititorul ar putea avea în acest moment o primă imagine despre ceea ce JUnit 5 pune la dispoziţie şi poate începe scrierea unor prime teste folosind acest framework.

VIDEO: NUMĂRULUI 125

Sponsori

  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • Connatix
  • BoatyardX
  • AboutYou
  • Colors in projects

VIDEO: EXTRA

Cătălin Tudose a mai scris