JUnit Verwachte uitzonderingstest: @Test(verwacht)

โšก Slimme samenvatting

JUnit Bij exception testing wordt bevestigd dat een methode de fout genereert die deze zou moeten genereren, met behulp van de optionele parameter `expected` van de `@Test`-annotatie. JUnit 4 en de assertThrows-methode in JUnit 5.

  • ๐Ÿ”˜ Doel: Bewijs dat ongeldige invoer de gedocumenteerde uitzondering oplevert in plaats van een stilzwijgend foutief antwoord.
  • โ˜‘๏ธ Syntax: @Test(expected = ArithmeticException.class) slaagt alleen wanneer precies dat type uitzondering wordt gegooid.
  • โœ… Voorbeeld: JUnitHet bericht deelt door nul en AirthematicTest verwacht de resulterende ArithmeticException.
  • ๐Ÿงช alternatief: Een try-blok gevolgd door fail() stelt je in staat de opgevangen uitzondering te inspecteren voordat je er een assertie op uitvoert.
  • ๏ธ JUnit 5: `assertThrows` retourneert de opgevangen uitzondering, zodat zowel het bericht als de oorzaak kunnen worden gecontroleerd.
  • ๐Ÿ“Œ Valkuil: De verwachte parameter wordt doorgegeven waar de uitzondering ook optreedt, wat een fout in de configuratiecode kan maskeren.

JUnit Verwachte uitzonderingstest met behulp van de parameter @Test(expected)

JUnit biedt de mogelijkheid om trace de uitzondering en ook om te controleren of de code de verwachte uitzondering genereert of niet.

JUnit 4 biedt een eenvoudige en leesbare manier voor het testen op uitzonderingen. Je kunt het volgende gebruiken:

  • De optionele parameter (verwacht) van de @Test-annotatieen
  • Naar trace de informatie, โ€œfail()โ€ kan worden gebruikt.

Terwijl het testen van Bij een uitzondering moet u ervoor zorgen dat de uitzonderingsklasse die u in die optionele parameter van de opgeeft, correct is. @Test-annotatie is dezelfde uitzondering die de methode daadwerkelijk genereert. Dit komt omdat je een uitzondering verwacht van de methode die je aanroept. testen van een eenheidanders onze JUnit proef zou mislukken.

Voorbeeld: @Test(expected = IllegalArgumentException.class)

Met de parameter "expected" kunt u de naam van de uitzondering specificeren die onze test mogelijk zal genereren. In het bovenstaande voorbeeld gebruikt u "IllegalArgumentException", die door de test wordt gegenereerd als een ontwikkelaar een argument gebruikt dat niet is toegestaan.

Voorbeeld met @Test(expected)

Laten we het testen van uitzonderingen begrijpen door een voorbeeld te maken. Java klasse met een methode die een uitzondering genereert uitzonderingJe zult het afhandelen en testen in een testklasse. Overweeg dit eens. JUnitHet bestand Message.java bevat een methode die een wiskundige bewerking uitvoert. De deling op regel 14 deelt door nul, waardoor de methode altijd een "ArithmeticException" genereert. Zie hieronder:

JUnitBerichtklasse in Eclipse printMessage deelt door nul op regel 14

package guru99.junit;

public class JUnitMessage{

	private String message;

	public JUnitMessage(String message) {
		this.message = message;
	}

public void printMessage(){

	System.out.println(message); 
	int divide=1/0;

}

public String printHiMessage(){ 

	message="Hi!" + message;
	
	System.out.println(message);

	return message;
}

}

Code Uitleg:

  • Code Regel 7: Een geparametriseerde constructor maken met veldinitialisatie.
  • Code Lijn 11-14: Een methode ontwikkelen voor de wiskundige bewerking.
  • Code Regel 18: Een andere methode creรซren om een โ€‹โ€‹bericht af te drukken.
  • Code Regel 20: Een nieuwe string maken om een โ€‹โ€‹bericht af te drukken.
  • Code Regel 22: Het nieuwe bericht dat in regel 20 is aangemaakt, wordt afgedrukt.

Laten we een testklasse maken voor het bovenstaande. Java klasse om de uitzondering te verifiรซren.

Hieronder ziet u de testklasse die de uitzondering (hier ArithmeticException) test die hierboven wordt gegenereerd. Java klasse:

AirthematicTest.java

De onderstaande schermafbeelding toont dezelfde test in de editor, waar het bestand is opgeslagen als AirthematicTest1, met de verwachte parameter gemarkeerd op regel 13:

Luchtthema-test 1 klas in Eclipse met @Test(expected = ArithmeticException.class) gemarkeerd op regel 13

package guru99.junit;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class AirthematicTest {

	public String message = "Saurabh";
	
	JUnitMessage junitMessage = new JUnitMessage(message);
	
	@Test(expected = ArithmeticException.class)
	public void testJUnitMessage(){

		System.out.println("Junit Message is printing ");
		junitMessage.printMessage();

	}

	@Test
	public void testJUnitHiMessage(){ 
		message="Hi!" + message;
		System.out.println("Junit Message is printing ");
		assertEquals(message, junitMessage.printHiMessage());
	
	}
}

Code Uitleg:

  • Code Regel 13: We gebruiken de `@Test`-annotatie om onze test te maken. Wanneer je de methode van de bovenstaande klasse uitvoert, wordt er een wiskundige bewerking uitgevoerd. Hier wordt een `ArithmeticException` verwacht, dus die geef je op als parameter in `@Test`.
  • Code Regel 17: printMessage() aanroepen vanuit JUnitBericht.java.
  • Code Lijn 21-22: Een nieuwe testmethode maken om het bericht "Hi" te controleren, dit keer zonder de verwachte parameter.

De klasse bevat twee testmethoden, waardoor beide methoden bij รฉรฉn uitvoering worden uitgevoerd: de methode die een ArithmeticException verwacht en de methode die een controle uitvoert op de geretourneerde tekenreeks.

Let op: Dit voorbeeld wordt in het originele materiaal onder drie namen genoemd: in de code wordt de klasse AirthematicTest genoemd, in de schermafbeelding van de editor staat AirthematicTest1 en in de resultaatweergave wordt JunitTestExample weergegeven. De code is in alle gevallen identiek; alleen de bestandsnaam verschilt.

Laten we het uitvoeren en het resultaat controleren. JUnit Onderstaande weergave laat de uitvoering zien JunitTestExample.java.

Output:

Hier is de uitvoer, die een succesvolle test zonder fouten laat zien. trace zoals hieronder weergegeven:

Eclipse JUnit Rapportage van de weergave: Runs 2/2 met nul fouten en nul mislukkingen voor JunitTestExample

Beide methoden zijn groen. De eerste slaagt omdat de gedeclareerde ArithmeticException daadwerkelijk is opgetreden, en de tweede slaagt omdat de geretourneerde tekenreeks overeenkomt. Als de deling nooit een uitzondering had gegenereerd, JUnit De eerste methode zou zijn mislukt met de melding "Verwachte uitzondering: java.lang.ArithmeticException".

Drie manieren om een โ€‹โ€‹uitzondering te testen in JUnit 4

De verwachte parameter is de kortste van de drie. JUnit Vier uitdrukkingen, maar het is niet altijd de juiste. De tabel vergelijkt ze aan de hand van twee vragen die de keuze bepalen: kun je iets zeggen over de boodschap, en weet je welke lijn je hebt getrokken?

Aanpak Bevestigt dit de boodschap? Speldt de werplijn vast? Best voor
@Test(expected = X.class) Nee Nee โ€” elke regel in de methode kan een foutmelding geven. Korte tests waarbij alleen het uitzonderingstype ertoe doet.
probeer / faal() / vang Ja, binnenin het opvangblok. Ja, alleen het beveiligde gesprek wordt bekeken. Tests die het bericht of de oorzaak moeten onderzoeken.
@Rule ExpectedException Ja, via expectMessage(). Nee Legacy-suites zijn al gebouwd op regels.

Het fail()-idioom dat in de inleiding wordt genoemd, ziet er als volgt uit. Als de aanroep geen uitzondering genereert, wordt fail() uitgevoerd en rapporteert de test het bericht dat je hebt geschreven:

@Test
public void testDivideByZero() {
    try {
        junitMessage.printMessage();
        fail("Expected an ArithmeticException");
    } catch (ArithmeticException e) {
        assertEquals("/ by zero", e.getMessage());
    }
}

De ExpectedException-regel bevindt zich tussen de twee in. Deze is afgekeurd in JUnit 4.13 ten gunste van de hierna beschreven assertThrows-methode, dus nieuw JUnit 4 tests zouden dit niet moeten overnemen.

Hoe test je uitzonderingen in JUnit 5 met assertThrows()

JUnit 5 verwijdert de verwachte parameter volledig uit @Test. Jupiter levert assertThrows()Deze functie neemt de uitzonderingsklasse en een lambda-uitdrukking met de te testen code als argumenten. De functie retourneert de opgevangen uitzondering, zodat het bericht, de oorzaak en eventuele aangepaste velden daarna gecontroleerd kunnen worden.

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

public class AirthematicJupiterTest {

    JUnitMessage junitMessage = new JUnitMessage("Saurabh");

    @Test
    public void testJUnitMessage() {
        ArithmeticException thrown = assertThrows(
                ArithmeticException.class,
                () -> junitMessage.printMessage());
        assertEquals("/ by zero", thrown.getMessage());
    }
}

Drie gerelateerde beweringen Maak het gezin compleet:

  • assertThrows accepteert het uitzonderingstype of een subklasse daarvan.
  • assertThrowsExactly Een subklasse wordt afgewezen, dus alleen het benoemde type wordt geaccepteerd.
  • assertDoesNotThrow Het stelt de tegenovergestelde verwachting vast, namelijk dat het blok netjes wordt voltooid.

De JUnit 4 code op deze pagina werkt nog steeds op de JUnit Het platform draait op de oude engine, dus er hoeft niets van het bovenstaande te worden herschreven om te blijven werken tijdens een projectmigratie.

Veelgemaakte fouten bij het testen van uitzonderingen in JUnit

Uitzonderingstests falen op een klein aantal herkenbare manieren. Elke regel vermeldt het symptoom, de oorzaak en de oplossing.

Symptoom Veroorzaken Bepalen
Verwachte uitzondering: java.lang.ArithmeticException De methode is succesvol voltooid zonder fouten. Controleer of de invoer daadwerkelijk ongeldig is en voer het programma opnieuw uit.
De test is geslaagd, maar de verkeerde lijn is doorgestuurd. De verwachte parameter observeert de hele methode, inclusief de setup. Verplaats de setup naar een andere plek, of schakel over op assertThrows rondom รฉรฉn specifieke aanroep.
Onverwerkt uitzonderingstype in de editor Er wordt een gecontroleerde uitzondering gegenereerd, maar deze wordt nooit gedeclareerd. Voeg throws toe aan de methodehandtekening van de test.
Test slaagt voor een subklasse die u niet bedoeld had. assertThrows accepteert subklassen van het genoemde type. Gebruik assertThrowsExactly voor een strikte typeovereenkomst.
'expected' is geen geldig attribuut. De test is gecompileerd met behulp van de Jupiter @Test-annotatie. Importeer org.junit.Test voor JUnit 4, of ga naar assertThrows.

De laatste regel is degene waar de meeste mensen tijdens de migratie tegenaan lopen, omdat beide annotaties @Test heten en alleen de import ze van elkaar onderscheidt. Keeping een JUnit versie per testcase De les vermijdt het hele probleem.

Veelgestelde vragen

De verwachte parameter kan geen bericht controleren. Plaats de aanroep in een try-blok, roep fail() direct daarna aan en controleer getMessage() binnen het catch-blok. JUnit Stap 5 maakt dit eenvoudiger omdat assertThrows de opgevangen uitzondering retourneert.

JUnit De test mislukt en meldt "Verwachte uitzondering" gevolgd door de klasse die je hebt genoemd. Er wordt verder niets gemeld, dus een test die nooit een uitzondering genereert, ziet er identiek uit aan een test waarvan het gedrag in de productiecode stilletjes is gewijzigd.

AI-assistenten lezen een methode, maken een lijst van de invoerwaarden die elke throw-instructie bereiken en stellen per vertakking een test op. Beschouw de uitvoer als uitgangspunt: de assistent leidt het uitzonderingstype af uit de code, zodat een onjuiste throw-instructie correct in de test wordt opgenomen.

Copilot Volgt de stijl die al in het bestand aanwezig is, dus een gemengd project krijgt een mix. Controleer de importregel voordat u een suggestie accepteert, want org.junit.Test en org.junit.jupiter.api.Test zien er identiek uit in de editor.

Het bestaat nog steeds, maar het is in 2010 afgeschaft. JUnit 4.13 en nooit geporteerd naar Jupiter. Bestaande testsuites kunnen het behouden; nieuwe tests moeten assertThrows gebruiken, wat beter leesbaar is en geen openbaar regelveld nodig heeft.

Ja. De lambda-parameter is een Executable, die is gedeclareerd om een โ€‹โ€‹Throwable te gooien, dus een gecontroleerde uitzondering heeft geen throws-clausule nodig in de testmethode zelf. Hetzelfde geldt voor de JUnit 4. Probeer een idioom te herkennen.

`assertThrows` accepteert elke subklasse van het opgegeven type, dus het verwachten van een `RuntimeException` geeft ook een `NullPointerException` door. Gebruik `assertThrowsExactly` wanneer de exacte klasse ertoe doet, of geef het meest specifieke type op dat u daadwerkelijk verwacht.

Alleen wanneer de uitzondering deel uitmaakt van de contract. Het testen van een uitzondering: de methode belooft nooit om vergrendelingen te gooien bij onbedoeld gedrag en maakt refactoring moeilijker, wat het doel van de test tenietdoet.

Vat dit bericht samen met: