Java >> Java tutorial >  >> Tag >> JUnit

Vejledning til JUnit 4 regler

1. Oversigt

I denne øvelse vil vi tage et kig på funktionen Regler, der leveres af JUnit 4-biblioteket.

Vi begynder med at introducere JUnit-regelmodellen, før vi går gennem de vigtigste basisregler, som distributionen giver. Derudover vil vi også se, hvordan man skriver og bruger vores egen tilpassede JUnit-regel.

For at lære mere om test med JUnit, se vores omfattende JUnit-serie.

Bemærk, at hvis du bruger JUnit 5, er reglerne blevet erstattet af udvidelsesmodellen.

2. Introduktion til JUnit 4-regler

JUnit 4-regler giver en fleksibel mekanisme til at forbedre test ved at køre noget kode omkring en testcase-udførelse . På en eller anden måde svarer det til at have @Before og @After annoteringer i vores testklasse.

Lad os forestille os, at vi ønskede at oprette forbindelse til en ekstern ressource såsom en database under testopsætningen og derefter lukke forbindelsen, når vores test er færdig. Hvis vi vil bruge den database i flere test, ender vi med at duplikere den kode i hver test.

Ved at bruge en regel kan vi have alt isoleret ét sted og nemt genbruge koden fra flere testklasser.

3. Brug af JUnit 4-regler

Så hvordan kan vi bruge regler? Vi kan bruge JUnit 4 regler ved at følge disse enkle trin:

  • Tilføj en offentlig felt til vores testklasse og sørg for, at typen af ​​dette felt er en undertype af org.junit.rules.TestRule grænseflade
  • Kommenter feltet med @reglen anmærkning

I næste afsnit vil vi se, hvilke projektafhængigheder vi skal bruge for at komme i gang.

4. Maven Dependencies

Lad os først tilføje de projektafhængigheder, vi skal bruge til vores eksempler. Vi har kun brug for JUnit 4-hovedbiblioteket:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

Som altid kan vi få den seneste version fra Maven Central.

5. Regler angivet i distributionen

Selvfølgelig giver JUnit en række nyttige, foruddefinerede regler som en del af biblioteket . Vi kan finde alle disse regler i org.junit.rules pakke.

I dette afsnit vil vi se nogle eksempler på, hvordan du bruger dem.

5.1. Temporary Folder Regel

Når vi tester, har vi ofte brug for adgang til en midlertidig fil eller mappe. Det kan dog være besværligt at administrere oprettelsen og sletningen af ​​disse filer. Brug af Temporary Folder regel, kan vi administrere oprettelsen af ​​filer og mapper, der skal slettes, når testmetoden afsluttes :

@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();

@Test
public void givenTempFolderRule_whenNewFile_thenFileIsCreated() throws IOException {
    File testFile = tmpFolder.newFile("test-file.txt");

    assertTrue("The file should have been created: ", testFile.isFile());
    assertEquals("Temp folder and test file should match: ", 
      tmpFolder.getRoot(), testFile.getParentFile());
}

Som vi kan se, definerer vi først Temporary Folder regel tmpFolder . Derefter opretter vores testmetode en fil kaldet test-file.txt i den midlertidige mappe. Vi tjekker derefter, at filen er oprettet og findes, hvor den skal. Rigtig fint og enkelt!

Når testen er færdig, skal den midlertidige mappe og fil slettes. Denne regel kontrollerer dog ikke, om sletningen er vellykket eller ej.

Der er også et par andre interessante metoder, der er værd at nævne i denne klasse:

  • newFile()

    Hvis vi ikke angiver noget filnavn, opretter denne metode en ny fil med tilfældigt navn.

  • newFolder(String... folderNames)

    For at oprette rekursivt dybe midlertidige mapper kan vi bruge denne metode.

  • newFolder()

    Ligeledes er newFolder() metoden opretter en tilfældigt navngivet ny mappe.

En god tilføjelse, der er værd at nævne, er, at startende med version 4.13, Temporary Folder regel tillader verifikation af slettede ressourcer:

@Rule 
public TemporaryFolder folder = TemporaryFolder.builder().assureDeletion().build();

Hvis en ressource ikke kan slettes, mislykkes testen med en AssertionError .

Endelig, i JUnit 5, kan vi opnå den samme funktionalitet ved at bruge den midlertidige mappeudvidelse.

5.2. ExpectedException Regel

Som navnet antyder, kan vi bruge ExpectedException regel for at bekræfte, at en eller anden kode afgiver en forventet undtagelse:

@Rule
public final ExpectedException thrown = ExpectedException.none();

@Test
public void givenIllegalArgument_whenExceptionThrown_MessageAndCauseMatches() {
    thrown.expect(IllegalArgumentException.class);
    thrown.expectCause(isA(NullPointerException.class));
    thrown.expectMessage("This is illegal");

    throw new IllegalArgumentException("This is illegal", new NullPointerException());
}

Som vi kan se i eksemplet ovenfor, erklærer vi først ExpectedException Herske. Så i vores test hævder vi, at en IllegalArgumentException er smidt.

Ved at bruge denne regel kan vi også verificere nogle andre egenskaber ved undtagelsen, såsom beskeden og årsagen.

For en dybdegående guide til at teste undtagelser med JUnit, se vores fremragende guide til, hvordan du gør en undtagelse gældende.

5.3. Testnavn Regel

Forenklet sagt, TestName regel giver det aktuelle testnavn i en given testmetode:

@Rule public TestName name = new TestName();

@Test
public void givenAddition_whenPrintingTestName_thenTestNameIsDisplayed() {
    LOG.info("Executing: {}", name.getMethodName());
    assertEquals("givenAddition_whenPrintingTestName_thenTestNameIsDisplayed", name.getMethodName());
}

I dette trivielle eksempel, når vi kører enhedstesten, skulle vi se testnavnet i outputtet:

INFO  c.baeldung.rules.JUnitRulesUnitTest - 
    Executing: givenAddition_whenPrintingTestName_thenTestNameIsDisplayed

5.4. Timeout Regel

I dette næste eksempel tager vi et kig på Timeout Herske. Denne regel tilbyder et nyttigt alternativ til at bruge timeout-parameteren på en individuel testannotering .

Lad os nu se, hvordan du bruger denne regel til at indstille en global timeout på alle testmetoderne i vores testklasse:

@Rule
public Timeout globalTimeout = Timeout.seconds(10);

@Test
public void givenLongRunningTest_whenTimout_thenTestFails() throws InterruptedException {
    TimeUnit.SECONDS.sleep(20);
}

I ovenstående trivielle eksempel definerer vi først en global timeout for alle testmetoder på 10 sekunder . Så definerer vi bevidst en test, som vil tage længere end 10 sekunder.

Når vi kører denne test, skulle vi se en testfejl:

org.junit.runners.model.TestTimedOutException: test timed out after 10 seconds
...

5.5. ErrorCollector Regel

Dernæst skal vi tage et kig på ErrorCollector Herske. Denne regel tillader at udførelsen af ​​en test fortsætter, efter at det første problem er fundet .

Lad os se, hvordan vi kan bruge denne regel til at indsamle alle fejl og rapportere dem alle på én gang, når testen afsluttes:

@Rule 
public final ErrorCollector errorCollector = new ErrorCollector();

@Test
public void givenMultipleErrors_whenTestRuns_thenCollectorReportsErrors() {
    errorCollector.addError(new Throwable("First thing went wrong!"));
    errorCollector.addError(new Throwable("Another thing went wrong!"));
        
    errorCollector.checkThat("Hello World", not(containsString("ERROR!")));
}

I ovenstående eksempel tilføjer vi to fejl til samleren. Når vi kører testen, fortsætter udførelsen, men testen mislykkes til sidst.

I outputtet vil vi se begge fejl rapporteret:

java.lang.Throwable: First thing went wrong!
...
java.lang.Throwable: Another thing went wrong!

5.6. Verifikator Regel

Verifikatoren regel er en abstrakt basisklasse, som vi kan bruge, når vi ønsker at verificere yderligere adfærd fra vores test . Faktisk er ErrorCollector regel, vi så i sidste afsnit, udvider denne klasse.

Lad os nu tage et kig på et trivielt eksempel på at definere vores egen verifikator:

private List messageLog = new ArrayList();

@Rule
public Verifier verifier = new Verifier() {
    @Override
    public void verify() {
        assertFalse("Message Log is not Empty!", messageLog.isEmpty());
    }
};

Her definerer vi en ny Verifikator og tilsidesæt verify() metode til at tilføje noget ekstra verifikationslogik. I dette enkle eksempel kontrollerer vi blot, at meddelelsesloggen i vores eksempel ikke er tom.

Nu, når vi kører enhedstesten og tilføjer en besked, skulle vi se, at vores verifikator er blevet anvendt:

@Test
public void givenNewMessage_whenVerified_thenMessageLogNotEmpty() {
    // ...
    messageLog.add("There is a new message!");
}

5.7. DisableOnDebug Regel

Nogle gange vil vi måske deaktivere en regel, når vi fejlretter . For eksempel er det ofte ønskeligt at deaktivere en Timeout regel ved fejlretning for at undgå, at vores test ophører og fejler, før vi har haft tid til at fejlfinde den ordentligt.

DisableOnDebug Regel gør præcis dette og giver os mulighed for at mærke visse regler, der skal deaktiveres ved fejlretning:

@Rule
public DisableOnDebug disableTimeout = new DisableOnDebug(Timeout.seconds(30));

I eksemplet ovenfor kan vi se, at for at bruge denne regel, overgiver vi simpelthen den regel, vi vil deaktivere, til konstruktøren.

Den største fordel ved denne regel er, at vi kan deaktivere regler uden at foretage ændringer i vores testklasser under fejlretning.

5.8. ExternalResource Regel

Når vi skriver integrationstest, kan vi typisk ønske at opsætte en ekstern ressource før en test og rive den ned bagefter. Heldigvis giver JUnit endnu en praktisk basisklasse til dette.

Vi kan udvide den abstrakte klasse ExternalResource at konfigurere en ekstern ressource før en test, såsom en fil eller en databaseforbindelse. Faktisk er Temporary Folder regel, vi så tidligere, udvider ExternalResource .

Lad os tage et hurtigt kig på, hvordan vi kan udvide denne klasse:

@Rule
public final ExternalResource externalResource = new ExternalResource() {
    @Override
    protected void before() throws Throwable {
        // code to set up a specific external resource.
    };
    
    @Override
    protected void after() {
        // code to tear down the external resource
    };
};

I dette eksempel, når vi definerer en ekstern ressource, skal vi blot tilsidesætte before() metode og after() metode for at opsætte og rive vores eksterne ressource ned.

6. Anvendelse af klasseregler

Indtil nu har alle de eksempler, vi har set på, været anvendt på enkelt-testcase-metoder. Nogle gange vil vi dog måske anvende en regel på testklasseniveau . Vi kan opnå dette ved at bruge @ClassRule annotation.

Denne annotation fungerer meget på samme måde som @Rule men omslutter en regel omkring en hel test - den største forskel er, at det felt, vi bruger til vores klasseregel, skal være statisk:

@ClassRule
public static TemporaryFolder globalFolder = new TemporaryFolder();

7. Definering af en tilpasset JUnit-regel

Som vi har set, giver JUnit 4 en række nyttige regler ud af boksen. Selvfølgelig kan vi definere vores egne brugerdefinerede regler. For at skrive en tilpasset regel skal vi implementere TestRule grænseflade.

Lad os tage et kig på et eksempel på at definere en brugerdefineret testmetodenavneloggerregel:

public class TestMethodNameLogger implements TestRule {

    private static final Logger LOG = LoggerFactory.getLogger(TestMethodNameLogger.class);

    @Override
    public Statement apply(Statement base, Description description) {
        logInfo("Before test", description);
        try {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    base.evaluate();
                }
            };
        } finally {
            logInfo("After test", description);
        }
    }

    private void logInfo(String msg, Description description) {
        LOG.info(msg + description.getMethodName());
    }
}

Som vi kan se, er TestRule grænsefladen indeholder en metode kaldet apply(Statement, Description) som vi skal tilsidesætte for at returnere en forekomst af erklæring . Erklæringen repræsenterer vores test inden for JUnit-runtiden. Når vi kalder evaluate() metode, udfører dette vores test.

I dette eksempel logger vi en før og efter besked og inkluderer fra Beskrivelse gøre indsigelse mod metodenavnet på den individuelle test.

8. Brug af regelkæder

I dette sidste afsnit tager vi et kig på, hvordan vi kan bestille flere testregler ved hjælp af RuleChain regel:

@Rule
public RuleChain chain = RuleChain.outerRule(new MessageLogger("First rule"))
    .around(new MessageLogger("Second rule"))
    .around(new MessageLogger("Third rule"));

I ovenstående eksempel opretter vi en kæde af tre regler, der blot udskriver den besked, der er sendt til hver MessageLogger konstruktør.

Når vi kører vores test, vil vi se, hvordan kæden anvendes i rækkefølge:

Starting: First rule
Starting: Second rule
Starting: Third rule
Finished: Third rule
Finished: Second rule
Finished: First rule

9. Konklusion

For at opsummere har vi i dette selvstudium udforsket JUnit 4-reglerne i detaljer.

Først startede vi med at forklare, hvad regler er, og hvordan vi kan bruge dem. Dernæst tog vi et dybdegående kig på de regler, der følger med som en del af JUnit-distributionen.

Til sidst så vi på, hvordan vi kan definere vores egen tilpassede regel, og hvordan vi kæder regler sammen.

Som altid er den fulde kildekode til artiklen tilgængelig på GitHub.


Java tag