Java >> Java tutorial >  >> Tag >> assert

JUnit 5 Tutorial:Skrivning af påstande med JUnit 5 Assertion API

Dette blogindlæg beskriver, hvordan vi kan skrive påstande ved at bruge JUnit 5 assertion API. Efter at vi har afsluttet dette blogindlæg, gør vi:

  • Kan skrive grundlæggende påstande med JUnit 5.
  • Vid, hvordan vi kan tilpasse den fejlmeddelelse, der vises, når en påstand mislykkes.
  • Forstå, hvordan vi kan køre flere påstande som en påstandsgruppe.

Lad os begynde.

Skriv påstande med JUnit 5

Hvis vi vil skrive påstande ved at bruge "standard" JUnit 5 API, skal vi bruge org.junit.jupiter.api.Assertions klasse. Det giver static fabriksmetoder, som giver os mulighed for at sikre, at den angivne betingelse er sand, efter at systemet under test er blevet kørt.

Før vi ser nærmere på disse metoder, er vi nødt til at kende et par grundlæggende regler:

  • Hvis vi ønsker at angive en brugerdefineret fejlmeddelelse, der vises, når vores påstand mislykkes, skal vi sende denne meddelelse som den sidste metodeparameter for den påberåbte påstandsmetode.
  • Hvis vi vil sammenligne to værdier (eller objekter), skal vi overføre disse værdier (eller objekter) til den påberåbte påstandsmetode i denne rækkefølge:den forventede værdi (eller objekt) og den faktiske værdi (eller objekt).

Dernæst vil vi finde ud af, hvordan vi kan skrive påstande med Assertions klasse. Lad os starte med at finde ud af, hvordan vi kan skrive påstande for boolean værdier.

Bekræftelse af booleske værdier

Hvis vi ønsker at verificere, at en boolean værdien er true , skal vi bruge assertTrue() metode for Assertions klasse. Med ordene skal vi bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is true")
    class WhenBooleanIsTrue {

        @Test
        @DisplayName("Should be true")
        void shouldBeTrue() {
            assertTrue(true);
        }
    }
}

Hvis vi ønsker at verificere, at en boolean værdien er false , skal vi bruge assertFalse() metode for Assertions klasse. Med ordene skal vi bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertFalse;

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is false")
    class WhenBooleanIsFalse {

        @Test
        @DisplayName("Should be false")
        void shouldBeFalse() {
            assertFalse(false);
        }
    }
}

Dernæst vil vi finde ud af, hvordan vi kan verificere, at et objekt er null eller er ikke null .

Bekræftelse af, at et objekt er nul eller ikke er nul

Hvis vi vil verificere, at et objekt er null , skal vi bruge assertNull() metode for Assertions klasse. Med andre ord, vi skal bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNull;

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When object is null")
    class WhenObjectIsNull {

        @Test
        @DisplayName("Should be null")
        void shouldBeNull() {
            assertNull(null);
        }
    }
}

Hvis vi vil verificere, at et objekt ikke er null , skal vi bruge assertNotNull() metoden for Assertions klasse. Med andre ord, vi skal bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When object is not null")
    class WhenObjectIsNotNotNull {

        @Test
        @DisplayName("Should not be null")
        void shouldNotBeNull() {
            assertNotNull(new Object());
        }
    }
}

Lad os gå videre og finde ud af, hvordan vi kan bekræfte, at to objekter (eller værdier) er ens eller ikke er ens.

Bekræftelse af, at to objekter eller værdier er ens

Hvis vi vil verificere, at den forventede værdi (eller objekt) er lig med den faktiske værdi (eller objekt), skal vi bruge assertEquals() metode for Assertions klasse. For eksempel, hvis vi ønsker at sammenligne to Integer objekter, skal vi bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects are equal")
    class WhenTwoObjectsAreEqual {

        @Nested
        @DisplayName("When objects are integers")
        class WhenObjectsAreIntegers {

            private final Integer ACTUAL = 9;
            private final Integer EXPECTED = 9;

            @Test
            @DisplayName("Should be equal")
            void shouldBeEqual() {
                assertEquals(EXPECTED, ACTUAL);
            }
        }
    }
}

Hvis vi vil verificere, at den forventede værdi (eller objekt) ikke er lig med den faktiske værdi (eller objekt), skal vi bruge assertNotEquals() metode for Assertions klasse. For eksempel, hvis vi vil sammenligne to Integer objekter, skal vi bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNotEquals;

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects aren't equal")
    class WhenTwoObjectsAreNotEqual {

        @Nested
        @DisplayName("When objects are integers")
        class WhenObjectsAreIntegers {

            private final Integer ACTUAL = 9;
            private final Integer EXPECTED = 4;

            @Test
            @DisplayName("Should not be equal")
            void shouldNotBeEqual() {
                assertNotEquals(EXPECTED, ACTUAL);
            }
        }
    }
}

Dernæst vil vi finde ud af, hvordan vi kan skrive påstande til objektreferencer.

Påhævelse af objektreferencer

Hvis vi vil sikre, at to objekter refererer til det samme objekt, skal vi bruge assertSame() metode for Assertions klasse. Med andre ord, vi skal bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertSame;

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects refer to the same object")
    class WhenTwoObjectsReferToSameObject {

        private final Object ACTUAL = new Object();
        private final Object EXPECTED = ACTUAL;

        @Test
        @DisplayName("Should refer to the same object")
        void shouldReferToSameObject() {
            assertSame(EXPECTED, ACTUAL);
        }
    }
}

Hvis vi vil sikre, at to objekter ikke refererer til det samme objekt, skal vi bruge assertNotSame() metoden for Assertions klasse. Med andre ord, vi skal bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNotSame;

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects don't refer to the same object")
    class WhenTwoObjectsDoNotReferToSameObject {

        private final Object ACTUAL = new Object();
        private final Object EXPECTED = new Object();

        @Test
        @DisplayName("Should not refer to the same object")
        void shouldNotReferToSameObject() {
            assertNotSame(EXPECTED, ACTUAL);
        }
    }
}

Lad os gå videre og finde ud af, hvordan vi kan verificere, at to arrays er ens.

påstand om, at to arrays er ens

Hvis vi vil verificere, at to arrays er ens, skal vi bruge assertArrayEquals() metoden for Assertions klasse. For eksempel, hvis vi vil bekræfte, at to int arrays er ens, skal vi bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

@DisplayName("Write assertions for arrays")
class ArrayAssertionTest {

    @Nested
    @DisplayName("When arrays contain integers")
    class WhenArraysContainIntegers {

        final int[] ACTUAL = new int[]{2, 5, 7};
        final int[] EXPECTED = new int[]{2, 5, 7};

        @Test
        @DisplayName("Should contain the same integers")
        void shouldContainSameIntegers() {
            assertArrayEquals(EXPECTED, ACTUAL);
        }
    }
}

Dernæst vil vi finde ud af, hvordan wen kan verificere, at to iterables er ens.

påstand om, at to iterables er ens

Hvis vi vil verificere, at to iterables er dybt lige store, skal vi bruge assertIterableEquals() metoden for Assertions klasse. For eksempel, hvis vi vil bekræfte, at to Integer lister er dybt lige, skal vi bruge denne påstand:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertIterableEquals;

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we compare two lists")
    class WhenWeCompareTwoLists {

        private final List<Integer> FIRST = Arrays.asList(1, 2, 3);
        private final List<Integer> SECOND = Arrays.asList(1, 2, 3);

        @Test
        @DisplayName("Should contain the same elements")
        void shouldContainSameElements() {
            assertIterableEquals(FIRST, SECOND);
        }
    }
}

Lad os gå videre og finde ud af, hvordan vi kan skrive påstande for den undtagelse, der er smidt af systemet under test.

Skrive påstande for undtagelser

Hvis vi ønsker at skrive påstande for de undtagelser, der er smidt af systemet under test, skal vi bruge assertThrows() metode for Assertions klasse. Denne metode tager følgende metodeparametre:

  • En Class objekt, der angiver typen af ​​den forventede undtagelse.
  • En Executable objekt, der kalder systemet under test.
  • En valgfri fejlmeddelelse.

For eksempel, hvis vi ønsker at verificere, at systemet under test kaster en NullPointerException , vores påstand ser ud som følger:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should throw the correct exception")
    void shouldThrowCorrectException() {
        assertThrows(
                NullPointerException.class,
                () -> { throw new NullPointerException(); }
        );
    }
}

Fordi assertThrows() metoden returnerer det kastede undtagelsesobjekt, kan vi også skrive yderligere påstande for den kastede undtagelse. For eksempel, hvis vi ønsker at bekræfte, at den kastede undtagelse har den korrekte meddelelse, kan vi bruge følgende påstande:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should throw an exception that has the correct message")
    void shouldThrowAnExceptionWithCorrectMessage() {
        final NullPointerException thrown = assertThrows(
                NullPointerException.class,
                () -> { throw new NullPointerException("Hello World!"); }
        );
        assertEquals("Hello World!", thrown.getMessage());
    }
}

På den anden side, selvom en testmetode mislykkes, hvis systemet under test kaster en undtagelse, vil vi nogle gange udtrykkeligt hævde, at ingen undtagelse er kastet af den testede kode. Hvis dette er tilfældet, skal vi bruge assertDoesNotThrow() metode for Assertions klasse. Når vi ønsker at verificere, at der ikke er nogen undtagelse fra systemet, der testes, kan vi bruge en af ​​disse to muligheder:

Først , hvis vi ikke ønsker at skrive påstande for den værdi, der returneres af systemet under test, skal vi overføre følgende metodeparametre til assertDoesNotThrow() metode:

  • En Executable objekt, der kalder systemet under test.
  • En valgfri fejlmeddelelse.

Hvis vi for eksempel ønsker at verificere, at systemet under test ikke giver en undtagelse, ser vores påstand ud som følger:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should not throw an exception")
    void shouldNotThrowException() {
        assertDoesNotThrow(() -> {});
    }
}

Anden , hvis vi ønsker at skrive påstande for den værdi, der returneres af systemet under test, skal vi overføre følgende metodeparametre til assertDoesNotThrow() metode:

  • A ThrowingSupplier objekt, der kalder systemet under test (og returnerer returværdien).
  • En valgfri fejlmeddelelse.

For eksempel, hvis vi ønsker at verificere, at systemet under test ikke afgiver en undtagelse, OG vi ønsker at verificere, at systemet under test returnerer den korrekte meddelelse, ser vores påstand ud som følger:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should not throw an exception")
    void shouldNotThrowException() {
        String message = assertDoesNotThrow(() -> { return "Hello World!"; } );
        assertEquals("Hello World!", message);
    }
}

Dernæst vil vi finde ud af, hvordan vi kan skrive påstande for udførelsestiden for systemet under test.

Skrivning af påstande for udførelsestiden for det system, der testes

Hvis vi ønsker at sikre, at udførelsen af ​​systemet under test er afsluttet, før den angivne timeout overskrides, kan vi bruge assertTimeout() og assertTimeoutPreemptively() metoder for Assertions klasse. Begge disse metoder tager følgende metodeparametre:

  • A Duration objekt, der angiver timeout.
  • En Executable eller en ThrowingSupplier objekt, der kalder systemet under test.
  • En valgfri fejlmeddelelse, der vises, hvis den angivne timeout overskrides.

Selvom disse to metoder er ret ens, har de en afgørende forskel. Denne forskel forklares i det følgende:

  • Hvis vi bruger assertTimeout() metode, den medfølgende Executable eller ThrowingSupplier vil blive udført i samme tråd som den kode, der kalder den. Denne metode afbryder heller ikke udførelsen, hvis timeout overskrides.
  • Hvis vi bruger assertTimeoutPreemptively() metode, den medfølgende Executable eller ThrowingSupplier vil blive udført i en anden tråd end den kode, der kalder den. Denne metode afbryder også udførelsen, hvis timeout overskrides.

Som vi ser, kan vi verificere, at udførelsen af ​​systemet under test er afsluttet, før den angivne timeout overskrides ved at bruge en af ​​disse to muligheder:

Først , hvis vi ønsker at udførelsen ikke afbrydes hvis timeout overskrides, skal vi bruge assertTimeout() metode for Assertions klasse. For eksempel, hvis vi ønsker at verificere, at systemet under test returnerer beskeden:'Hej verden!' før den specificerede timeout (50ms) overskrides, skal vi skrive påstande, der ser ud som følger:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeout;

@DisplayName("Writing assertions for the execution time of the system under test")
class TimeoutAssertionTest {

    @Test
    @DisplayName("Should return the correct message before timeout is exceeded")
    void shouldReturnCorrectMessageBeforeTimeoutIsExceeded() {
        final String message = assertTimeout(Duration.ofMillis(50), () -> {
            Thread.sleep(20);
            return "Hello World!";
        });
        assertEquals("Hello World!", message);
    }
}

Anden , hvis vi ønsker at udførelsen afbrydes hvis timeout overskrides, skal vi bruge assertTimeoutPreemptively() metoden for Assertions klasse. For eksempel, hvis vi ønsker at verificere, at systemet under test returnerer beskeden:'Hej verden!' før den specificerede timeout (50ms) overskrides, skal vi skrive påstande, der ser ud som følger:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;

@DisplayName("Writing assertions for the execution time of the system under test")
class TimeoutAssertionTest {

    @Test
    @DisplayName("Should return the correct message before timeout is exceeded")
    void shouldReturnCorrectMessageBeforeTimeoutIsExceeded() {
        final String message = assertTimeoutPreemptively(Duration.ofMillis(50), () -> {
            Thread.sleep(20);
            return "Hello World!";
        });
        assertEquals("Hello World!", message);
    }
}

Vi kan nu skrive grundlæggende påstande med JUnit 5. Lad os gå videre og finde ud af, hvordan vi kan tilpasse de fejlmeddelelser, som vises af JUnit 5, hvis en påstand mislykkes.

Udgivelse af en brugerdefineret fejlmeddelelse

Som vi husker, hvis vi ønsker at angive en brugerdefineret fejlmeddelelse, der vises, når vores påstand mislykkes, skal vi sende denne meddelelse som den sidste metodeparameter for den påberåbte påstandsmetode. Vi kan oprette denne besked ved at bruge en af ​​disse to muligheder:

Først , kan vi oprette en ny String objekt og videregive dette objekt som den sidste metodeparameter for den påberåbte assertion assertion-metode. Dette er et godt valg, hvis vores fejlmeddelelse ikke har nogen parametre. For eksempel, hvis vi ønsker at give en brugerdefineret fejlmeddelelse for en påstand, som bekræfter, at en boolean værdien er false , skal vi skrive en påstand, der ser ud som følger:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertFalse;

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is false")
    class WhenBooleanIsFalse {

        @Test
        @DisplayName("Should be false")
        void shouldBeFalse() {
            assertFalse(false, "The boolean is not false");
        }
    }
}

Anden , kan vi oprette en meddelelsesleverandør (Supplier ) og videregive denne leverandør som den sidste metodeparameter for den påberåbte påstandsmetode. Hvis vi bruger denne tilgang, opretter JUnit 5 kun de faktiske fejlmeddelelser hvis vores påstand mislykkes. Derfor er dette et godt valg, hvis vi ønsker at oprette en "kompleks" fejlmeddelelse, der har parametre.

For eksempel, hvis vi ønsker at give en brugerdefineret fejlmeddelelse for en påstand, som bekræfter, at et kort indeholder den givne nøgle, skal vi skrive en påstand, der ser ud som følger:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertTrue;

@DisplayName("Writing assertions for maps")
class MapAssertionTest {

    private static final String KEY = "key";
    private static final String VALUE = "value";

    private Map<String, String> map;

    @BeforeEach
    void createAndInitializeMap() {
        map = new HashMap<>();
        map.put(KEY, VALUE);
    }

    @Test
    @DisplayName("Should contain the correct key")
    void shouldContainCorrectKey() {
        assertTrue(
                map.containsKey(KEY), 
                () -> String.format("The map doesn't contain the key: %s", KEY)
        );
    }
}

Dernæst vil vi finde ud af, hvordan vi kan gruppere påstande med JUnit 5.

Gruppere påstande

Hvis vi skal skrive en påstand for en tilstand, der kræver flere påstande, kan vi gruppere vores påstande ved at bruge assertAll() metoden for Assertions klasse. Denne metode tager følgende metodeparametre:

  • En valgfri overskrift, der identificerer den påståede tilstand.
  • En matrix, en Collection eller en Stream af Executable objekter, der påberåber sig vores påstande.

Når vi kalder assertAll() metode, kalder den alle specificerede påstande og rapporterer alle påstandsfejl, efter at alle påstande er blevet kørt.

Lad os antage, at vi skal skrive en påstand, som bekræfter, at en Person objektet har det korrekte navn. Kildekoden til Person klasse ser ud som følger:

public class Person {

    private String firstName;
    private String lastName;

    public Person() {}

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

Som vi kan se, hvis vi vil verificere, at en person har det korrekte navn, skal vi verificere, at den hævdede Person objektet har det korrekte for- og efternavn. Med andre ord skal vi skrive en påstand, der ser ud som følger:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("Group multiple assertions")
class GroupAssertionsTest {

    private static final String FIRST_NAME = "Jane";
    private static final String LAST_NAME = "Doe";

    private Person person;

    @BeforeEach
    void createPerson() {
        person = new Person();
        person.setFirstName(FIRST_NAME);
        person.setLastName(LAST_NAME);
    }

    @Test
    @DisplayName("Should have the correct name")
    void shouldHaveCorrectName() {
        assertAll("name",
                () -> assertEquals(FIRST_NAME, 
                        person.getFirstName(), 
                        "The first name is incorrect"
                ),
                () -> assertEquals(LAST_NAME, 
                        person.getLastName(), 
                        "The last name is incorrect"
                )
        );
    }
}

Vi kan nu skrive grundlæggende påstande med JUnit 5, give en brugerdefineret fejlmeddelelse, der vises, når en påstand mislykkes, og gruppere påstande med JUnit 5.

Lad os opsummere, hvad vi lærte af dette blogindlæg.

Oversigt

Dette blogindlæg har lært os fire ting:

  • Hvis vi vil skrive påstande ved at bruge "standard" JUnit 5 API, skal vi bruge org.junit.jupiter.api.Assertions klasse.
  • Hvis vi ønsker at angive en brugerdefineret fejlmeddelelse, der ikke har nogen parametre, skal vi oprette en ny String objekt og videregive dette objekt som den sidste metodeparameter for den påberåbte påstandsmetode.
  • Hvis vi ønsker at angive en "kompleks" fejlmeddelelse, der har parametre, skal vi oprette en meddelelsesleverandør (Supplier ) og videregive denne leverandør som den sidste metodeparameter for den påberåbte påstandsmetode.
  • Hvis vi skal skrive en påstand for en tilstand, der kræver flere påstande, kan vi gruppere vores påstande ved at bruge assertAll() metoden for Assertions klasse.

Java tag