Verspotten der Java-Enumeration, um einen Wert zum Testen des Fehlerfalls hinzuzufügen

70

Ich habe einen Enum- Schalter mehr oder weniger wie folgt:

public static enum MyEnum {A, B}

public int foo(MyEnum value) {
    switch(value) {
        case(A): return calculateSomething();
        case(B): return calculateSomethingElse();
    }
    throw new IllegalArgumentException("Do not know how to handle " + value);
}

und ich möchte, dass alle Zeilen von den Tests abgedeckt werden, aber da erwartet wird, dass der Code alle Möglichkeiten abdeckt, kann ich keinen Wert ohne die entsprechende case-Anweisung im Schalter angeben.

Das Erweitern der Enumeration um einen zusätzlichen Wert ist nicht möglich, und das Verspotten der Methode equals für die Rückgabe falsefunktioniert auch nicht, da der generierte Bytecode eine Sprungtabelle hinter den Vorhängen verwendet, um zum richtigen Fall zu gelangen ... Also habe ich mir gedacht dass vielleicht etwas schwarze Magie mit PowerMock oder so etwas erreicht werden könnte.

Vielen Dank!

bearbeiten :

Da mir die Aufzählung gehört, habe ich gedacht, ich könnte den Werten einfach eine Methode hinzufügen und so das Switch-Problem vollständig vermeiden. aber ich lasse die Frage, da es immer noch interessant ist.

fortran
quelle
@Melloware> ... Code, der die switch () - Anweisung ausführt Java löst eine java.lang.ArrayIndexOutOfBounds aus ... Ich habe das gleiche Problem. Führen Sie Ihren Test mit neuem Enum als erstes in Ihrer Testklasse aus. Ich habe einen Fehler mit diesem Problem erstellt: code.google.com/p/powermock/issues/detail?id=440
Marcin Stachniuk
Es funktioniert besser, wenn ich @PrepareForTest (MyEnum.class) auf Methodenebene verwende.
Marcin Stachniuk
1
Ein IlegalArgument, das aufgrund der klaren Eigenschaften der Aufzählung niemals geworfen werden kann, aber was Sie tun müssen, um Ihren Code zu bastardisieren, um zu testen, ob er mit dem Unmöglichen umgehen kann? Wenn Sie Ihre Zeilenübertragungsmetrik wirklich fetischisieren möchten, löschen Sie einfach die Zeile, die niemals ausgeführt werden kann.
Raedwald
13
@Raedwald 2 Gründe: Erstens könnte jemand anderes einen neuen Wert für die Aufzählung erstellen und vergessen, einen neuen Fall für den Schalter hinzuzufügen. Zweitens wird der Code ohne throwoder returnnach dem Wechsel nicht kompiliert .
Fortan
Nach Überlegung denke ich, lass es einfach ungetestet. Es gibt keinen illegalen Aufzählungswert, der die Ausnahme auslöst, und es ist schmerzhaft, sich zu verspotten. Ich denke, der Wurf ist gut, er ist zukunftssicher und nur sehr schwer zu testen. Den Aufwand nicht wert, IMHO.
Robert Bain

Antworten:

13

Wenn Sie Maven als Build-System verwenden können, können Sie einen viel einfacheren Ansatz verwenden. Definieren Sie einfach dieselbe Aufzählung mit einer zusätzlichen Konstante in Ihrem Testklassenpfad.

Angenommen, Sie haben Ihre Aufzählung wie folgt im Quellverzeichnis (src / main / java) deklariert:

package my.package;

public enum MyEnum {
    A,
    B
}

Jetzt deklarieren Sie genau dieselbe Aufzählung im Verzeichnis der Testquellen (src / test / java) wie folgt:

package my.package

public enum MyEnum {
    A,
    B,
    C
}

Die Tests sehen den Testklassenpfad mit der Aufzählung "überladen" und Sie können Ihren Code mit der Aufzählungskonstante "C" testen. Sie sollten dann Ihre IllegalArgumentException sehen.

Getestet unter Windows mit Maven 3.5.2, AdoptOpenJDK 11.0.3 und IntelliJ IDEA 2019.3.1

Frank S.
quelle
2
Dies ist eine ziemlich elegante Lösung! Ich weiß nicht, wie ich es damals komplett verpassen könnte. Es macht mir nur Sorgen, dass es schwierig sein könnte, sich bei wiederholter Klassendefinition auf die Vorrangregeln für Klassenpfade zu verlassen
fortran
Ich sehe diese Arbeit nicht mit Gradle. Ich denke, die Verwendung von PowerMockito in der Antwort hier scheint eine bessere "allgemeine" Antwort zu sein: stackoverflow.com/questions/5323505/…
Bret Royster
Eclipse scheint diese Lösung abzulehnenThe type MyEnum is already defined
Wutzebaer
61

Hier ist ein vollständiges Beispiel.

Der Code ähnelt fast Ihrem Original (nur vereinfachte bessere Testvalidierung):

public enum MyEnum {A, B}

public class Bar {

    public int foo(MyEnum value) {
        switch (value) {
            case A: return 1;
            case B: return 2;
        }
        throw new IllegalArgumentException("Do not know how to handle " + value);
    }
}

Und hier ist der Komponententest mit vollständiger Codeabdeckung. Der Test funktioniert mit Powermock (1.4.10), Mockito (1.8.5) und JUnit (4.8.2):

@RunWith(PowerMockRunner.class)
public class BarTest {

    private Bar bar;

    @Before
    public void createBar() {
        bar = new Bar();
    }

    @Test(expected = IllegalArgumentException.class)
    @PrepareForTest(MyEnum.class)
    public void unknownValueShouldThrowException() throws Exception {
        MyEnum C = mock(MyEnum.class);
        when(C.ordinal()).thenReturn(2);

        PowerMockito.mockStatic(MyEnum.class);
        PowerMockito.when(MyEnum.values()).thenReturn(new MyEnum[]{MyEnum.A, MyEnum.B, C});

        bar.foo(C);
    }

    @Test
    public void AShouldReturn1() {
        assertEquals(1, bar.foo(MyEnum.A));
    }

    @Test
    public void BShouldReturn2() {
        assertEquals(2, bar.foo(MyEnum.B));
    }
}

Ergebnis:

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.628 sec
Jonny Heggheim
quelle
5
Ich bin Ihrem Beispiel mit Mockito 1.9.0 und PowerMock 1.4.12 gefolgt und konnte eine neue Aufzählung in meine Liste einfügen. Der Code, der die switch () - Anweisung ausführt, löst jedoch eine java.lang.ArrayIndexOutOfBounds-Ausnahme aus, wie sie dort bekannt ist soll kein extra sein. Irgendwelche Gedanken?
Melloware
3
Falls jemand auf das Problem stößt, das @Melloware hatte, kann Folgendes hilfreich sein. Damit das obige Beispiel in meinen eigenen Tests funktioniert, musste ich ALLE Werte der ursprünglichen Aufzählung UND die verspottete in die Anweisung when / thenReturn einfügen und die Ordnungszahl korrekt festlegen. Wenn Sie einen zusätzlichen Wert verspotten, sollte die Ordnungszahl die Anzahl der Werte in Ihrer ursprünglichen nicht verspotteten Aufzählung sein.
JeroenHoek
2
Wie können Sie PowerMockito.mockStatic (MyEnum.class);? Es sollte java.lang.IllegalArgumentException geben: Kann die letzte Klasse nicht
unterordnen
Zumindest mit normalem Mockito wird die Ausnahme ausgelöst.
Borjab
1
Ausgezeichnet! Ich habe aber die Lösung etwas verbessert. An ist Whitebox.setInternalState(C, "ordinal", 2);es möglich foostatt zu bestehen 2. Und initialisiere fooals int foo = MyEnum.values().length;erste Saite (oben MyEnum C = PowerMockito.mock(MyEnum.class);)
Alexander Skvortsov
2

Anstatt eine radikale Bytecode-Manipulation zu verwenden, damit ein Test die letzte Zeile erreicht foo, würde ich ihn entfernen und mich stattdessen auf die statische Code-Analyse verlassen. Beispielsweise verfügt IntelliJ IDEA über die Codeinspektion "Enum- switchAnweisung, bei der der Fall übersehen wird", die eine Warnung für die fooMethode erzeugt, wenn eine fehlt case.

Rogério
quelle
1
Aus diesem Grund habe ich die Fail-Aktion außerhalb eines "Standard" -Falls platziert, um auch statische Analysen zuzulassen. Ich bin jedoch nicht bereit, eine Laufzeitprüfung zu entfernen und mich nur auf statische Analysen zu verlassen. Ich denke, beide sollten sich ergänzen.
Fortan
Das war mein Punkt, statische Analyse zu verwenden, um eine Testsuite + Codeabdeckung zu ergänzen. Wenn Sie es verwenden, wird die Zeile mit der throwAnweisung redundant und kann entfernt werden, da das Fehlen eines casein switchin von der IDE / dem Build erkannt wird.
Rogério
Ich denke, das ist eine gute Idee. Der Standardfall für eine Aufzählung ist nicht wirklich Code in dem Sinne, dass sein Teil der Anwendung, der jemals ausgeführt wird, sein Code, um ihn gegen etwas zu schützen, das Sie möglicherweise tun, was später einen Fehler verursachen könnte. Es ist besser, nur Ihre Anwendung zu codieren und sicherzustellen, dass sie korrekt ist. Gibt es für Sonar eine Regel "Enum-Switch-Anweisung, bei der Groß- und Kleinschreibung übersehen wird"?
user2800708
2

Wie Sie in Ihrer Bearbeitung angegeben haben, können Sie die Funktionalität in der Aufzählung selbst hinzufügen . Dies ist jedoch möglicherweise nicht die beste Option, da dies gegen das Prinzip "Eine Verantwortung" verstoßen kann. Eine andere Möglichkeit, dies zu erreichen, besteht darin, eine statische Zuordnung zu erstellen, die Aufzählungswerte als Schlüssel und die Funktionalität als Wert enthält. Auf diese Weise können Sie leicht testen, ob Sie für einen Aufzählungswert ein gültiges Verhalten haben, indem Sie alle Werte durchlaufen. Es könnte ein bisschen weit hergeholt an diesem Beispiel sein, aber das ist eine Technik , die ich oft zur Karte verwende Ressourcen - IDs zu Enum - Werten.

Bert Bruynooghe
quelle
1
Dies hilft nicht, insbesondere wenn Sie die Aufzählung nicht unter Ihrer Kontrolle haben. Ein Verbraucher könnte dann eine neuere Version der Aufzählung verwenden, die mehr Werte enthält, und ein Test, der überprüft, ob eine ordnungsgemäße Ausnahme ausgelöst oder eine Standardaktion ausgeführt wird, ist möglicherweise ziemlich sinnvoll.
Vampir
1

jMock (zumindest ab Version 2.5.1, die ich verwende) kann dies sofort tun. Sie müssen Ihre Mockery so einstellen, dass ClassImposterizer verwendet wird.

Mockery mockery = new Mockery();
mockery.setImposterizer(ClassImposterizer.INSTANCE);
MyEnum unexpectedValue = mockery.mock(MyEnum.class);
Kevin Peterson
quelle
1

Es reicht nicht aus, nur einen gefälschten Enum-Wert zu erstellen. Schließlich müssen Sie auch ein vom Compiler erstelltes Integer-Array bearbeiten.


Um einen gefälschten Enum-Wert zu erstellen, benötigen Sie nicht einmal ein spöttisches Framework. Sie können nur Objenesis verwenden , um eine neue Instanz der Enum - Klasse (ja, das funktioniert) und verwenden Sie dann Plain Old Java Reflexion auf die privaten Felder zu setzen nameund ordinalund haben Sie bereits Ihre neue Enum - Instanz.

Wenn Sie das Spock-Framework zum Testen verwenden, sieht dies ungefähr so ​​aus:

given:
    def getPrivateFinalFieldForSetting = { clazz, fieldName ->
        def result = clazz.getDeclaredField(fieldName)
        result.accessible = true
        def modifiers = Field.getDeclaredFields0(false).find { it.name == 'modifiers' }
        modifiers.accessible = true
        modifiers.setInt(result, result.modifiers & ~FINAL)
        result
    }

and:
    def originalEnumValues = MyEnum.values()
    MyEnum NON_EXISTENT = ObjenesisHelper.newInstance(MyEnumy)
    getPrivateFinalFieldForSetting.curry(Enum).with {
        it('name').set(NON_EXISTENT, "NON_EXISTENT")
        it('ordinal').setInt(NON_EXISTENT, originalEnumValues.size())
    }

Wenn die MyEnum.values()Methode auch die neue Aufzählung zurückgeben soll, können Sie jetzt entweder JMockit verwenden, um den values()Aufruf wie zu verspotten

new MockUp<MyEnum>() {
    @Mock
    MyEnum[] values() {
        [*originalEnumValues, NON_EXISTENT] as MyEnum[]
    }
}

oder Sie können wieder einfache alte Reflexion verwenden, um das $VALUESFeld wie folgt zu manipulieren :

given:
    getPrivateFinalFieldForSetting.curry(MyEnum).with {
        it('$VALUES').set(null, [*originalEnumValues, NON_EXISTENT] as MyEnum[])
    }

expect:
    true // your test here

cleanup:
    getPrivateFinalFieldForSetting.curry(MyEnum).with {
        it('$VALUES').set(null, originalEnumValues)
    }

Solange Sie sich nicht mit einem switchAusdruck befassen , sondern mit einigen ifs oder ähnlichem, kann entweder nur der erste Teil oder der erste und zweite Teil für Sie ausreichen.

Wenn Sie sich jedoch mit einem switchAusdruck befassen , z. B. eine 100% ige Abdeckung für den defaultFall, der eine Ausnahme auslöst, falls die Aufzählung wie in Ihrem Beispiel erweitert wird, werden die Dinge etwas komplizierter und gleichzeitig etwas einfacher.

Etwas komplizierter, da Sie ernsthafte Überlegungen anstellen müssen, um ein synthetisches Feld zu manipulieren, das der Compiler in einer synthetischen anonymen Innner-Klasse generiert, die der Compiler generiert. Daher ist es nicht wirklich offensichtlich, was Sie tun, und Sie sind an die tatsächliche Implementierung gebunden des Compilers, so dass dies in jeder Java-Version jederzeit oder sogar dann unterbrochen werden kann, wenn Sie unterschiedliche Compiler für dieselbe Java-Version verwenden. Es ist tatsächlich schon anders zwischen Java 6 und Java 8.

Ein bisschen einfacher, weil Sie die ersten beiden Teile dieser Antwort vergessen können, weil Sie überhaupt keine neue Enum-Instanz erstellen müssen, sondern nur eine manipulieren müssen int[], die Sie sowieso manipulieren müssen, um den Test für Sie durchzuführen wollen.

Ich habe kürzlich einen sehr guten Artikel dazu unter https://www.javaspecialists.eu/archive/Issue161.html gefunden .

Die meisten Informationen dort sind noch gültig, außer dass die innere Klasse, die die Switch-Map enthält, keine benannte innere Klasse mehr ist, sondern eine anonyme Klasse. Sie können sie also nicht getDeclaredClassesmehr verwenden, sondern müssen einen anderen Ansatz verwenden, der unten gezeigt wird.

Grundsätzlich funktioniert das Einschalten der Bytecode-Ebene nicht mit Aufzählungen, sondern nur mit Ganzzahlen. Also , was der Compiler tut , ist es eine anonyme innere Klasse erstellt (vorher eine benannte innere Klasse gemäß dem Artikel zu schreiben, das ist Java 6 vs. Java 8) , die ein statisches endgültiges hält int[]Feld genannt , $SwitchMap$net$kautler$MyEnumdie mit ganzen Zahlen 1, gefüllt 2, 3, ... an den Werteindizes MyEnum#ordinal().

Dies bedeutet, wenn der Code zum eigentlichen Schalter kommt, tut er dies

switch(<anonymous class here>.$SwitchMap$net$kautler$MyEnum[myEnumVariable.ordinal()]) {
    case 1: break;
    case 2: break;
    default: throw new AssertionError("Missing switch case for: " + myEnumVariable);
}

Wenn jetzt myEnumVariableder Wert NON_EXISTENTim ersten Schritt oben erstellt werden würde, würden Sie entweder einen erhalten, ArrayIndexOutOfBoundsExceptionwenn Sie einen ordinalWert festlegen , der größer als das vom Compiler generierte Array ist, oder Sie würden in beiden Fällen einen der anderen Switch-Case-Werte erhalten, wenn dies nicht der Fall ist Dies würde nicht helfen, den gewünschten defaultFall zu testen .

Sie können dieses int[]Feld jetzt abrufen und so reparieren, dass es eine Zuordnung für das Orinal Ihrer NON_EXISTENTEnum-Instanz enthält. Aber wie ich bereits sagte, defaultbrauchen Sie für genau diesen Anwendungsfall, in dem Sie den Fall testen , die ersten beiden Schritte überhaupt nicht. Stattdessen können Sie dem zu testenden Code einfach eine der vorhandenen Enum-Instanzen zuweisen und die Zuordnung einfach int[]so bearbeiten , dass der defaultFall ausgelöst wird.

Für diesen Testfall ist also nur Folgendes erforderlich, das wiederum in Spock (Groovy) -Code geschrieben ist. Sie können es jedoch auch problemlos an Java anpassen:

given:
    def getPrivateFinalFieldForSetting = { clazz, fieldName ->
        def result = clazz.getDeclaredField(fieldName)
        result.accessible = true
        def modifiers = Field.getDeclaredFields0(false).find { it.name == 'modifiers' }
        modifiers.accessible = true
        modifiers.setInt(result, result.modifiers & ~FINAL)
        result
    }

and:
    def switchMapField
    def originalSwitchMap
    def namePrefix = ClassThatContainsTheSwitchExpression.name
    def classLoader = ClassThatContainsTheSwitchExpression.classLoader
    for (int i = 1; ; i++) {
        def clazz = classLoader.loadClass("$namePrefix\$$i")
        try {
            switchMapField = getPrivateFinalFieldForSetting(clazz, '$SwitchMap$net$kautler$MyEnum')
            if (switchMapField) {
                originalSwitchMap = switchMapField.get(null)
                def switchMap = new int[originalSwitchMap.size()]
                Arrays.fill(switchMap, Integer.MAX_VALUE)
                switchMapField.set(null, switchMap)
                break
            }
        } catch (NoSuchFieldException ignore) {
            // try next class
        }
    }

when:
    testee.triggerSwitchExpression()

then:
    AssertionError ae = thrown()
    ae.message == "Unhandled switch case for enum value 'MY_ENUM_VALUE'"

cleanup:
    switchMapField.set(null, originalSwitchMap)

In diesem Fall benötigen Sie überhaupt kein spöttisches Framework. Eigentlich würde es Ihnen sowieso nicht helfen, da kein mir bekanntes Mocking-Framework es Ihnen ermöglicht, einen Array-Zugriff zu verspotten. Sie könnten JMockit oder ein beliebiges Verspottungsframework verwenden, um den Rückgabewert von zu verspotten ordinal(), aber dies würde wiederum einfach zu einem anderen Switch-Zweig oder einer AIOOBE führen.

Dieser Code, den ich gerade gezeigt habe, ist:

  • Es durchläuft die anonymen Klassen innerhalb der Klasse, die den switch-Ausdruck enthält
  • in denen sucht es nach dem Feld mit der Schalterzuordnung
  • Wird das Feld nicht gefunden, wird die nächste Klasse ausprobiert
  • Wenn a von ClassNotFoundExceptionausgelöst wird Class.forName, schlägt der Test fehl, was beabsichtigt ist, da dies bedeutet, dass Sie den Code mit einem Compiler kompiliert haben, der einer anderen Strategie oder einem anderen Namensmuster folgt. Daher müssen Sie mehr Informationen hinzufügen, um verschiedene Compilerstrategien für das Einschalten abzudecken Aufzählungswerte. Wenn die Klasse mit dem Feld gefunden wird, breakverlässt sie die for-Schleife und der Test kann fortgesetzt werden. Diese ganze Strategie hängt natürlich davon ab, dass anonyme Klassen ab 1 und ohne Lücken nummeriert werden, aber ich hoffe, dass dies eine ziemlich sichere Annahme ist. Wenn Sie es mit einem Compiler zu tun haben, bei dem dies nicht der Fall ist, muss der Suchalgorithmus entsprechend angepasst werden.
  • Wenn das Switch-Map-Feld gefunden wird, wird ein neues int-Array derselben Größe erstellt
  • Das neue Array ist gefüllt, Integer.MAX_VALUEwodurch normalerweise der defaultFall ausgelöst werden sollte, solange Sie keine Aufzählung mit 2.147.483.647 Werten haben
  • Das neue Array wird dem Switch-Map-Feld zugewiesen
  • Die for-Schleife bleibt mit break
  • Jetzt kann der eigentliche Test durchgeführt werden, wodurch der auszuwertende Schalterausdruck ausgelöst wird
  • Schließlich (in einem finallyBlock, wenn Sie Spock nicht verwenden, in einem cleanupBlock, wenn Sie Spock verwenden), um sicherzustellen, dass dies keine Auswirkungen auf andere Tests derselben Klasse hat, wird die ursprüngliche Switch-Map wieder in das Switch-Map-Feld eingefügt
Vampir
quelle
0

Zuallererst kann Mockito Scheindaten erstellen, die ganzzahlig sein können usw. Es kann keine richtige Aufzählung erstellen, da die Aufzählung eine bestimmte Anzahl von Ordnungsnamenwerten usw. hat. Wenn ich also eine Aufzählung habe

public enum HttpMethod {
      GET, POST, PUT, DELETE, HEAD, PATCH;
}

Ich habe also insgesamt 5 Ordnungszahlen in enum HttpMethod, aber mockito weiß es nicht. Mockito erstellt die ganze Zeit Scheindaten und deren Null und Sie werden am Ende einen Nullwert übergeben. Hier wird also eine Lösung vorgeschlagen, bei der Sie die Ordnungszahl randomisieren und eine richtige Aufzählung erhalten, die für andere Tests bestanden werden kann

import static org.mockito.Mockito.mock;

import java.util.Random;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.internal.util.reflection.Whitebox;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.amazonaws.HttpMethod;




//@Test(expected = {"LoadableBuilderTestGroup"})
//@RunWith(PowerMockRunner.class)
public class testjava {
   // private static final Class HttpMethod.getClass() = null;
    private HttpMethod mockEnumerable;

    @Test
    public void setUpallpossible_value_of_enum () {
        for ( int i=0 ;i<10;i++){
            String name;
            mockEnumerable=    Matchers.any(HttpMethod.class);
            if(mockEnumerable!= null){
                System.out.println(mockEnumerable.ordinal());
                System.out.println(mockEnumerable.name());

                System.out.println(mockEnumerable.name()+"mocking suceess");
            }
            else {
                //Randomize all possible  value of  enum 
                Random rand = new Random();
                int ordinal = rand.nextInt(HttpMethod.values().length); 
                // 0-9. mockEnumerable=
                mockEnumerable= HttpMethod.values()[ordinal];
                System.out.println(mockEnumerable.ordinal());
                System.out.println(mockEnumerable.name());
            }
        }
    }







    @Test
    public void setUpallpossible_value_of_enumwithintany () {
        for ( int i=0 ;i<10;i++){
            String name;
            mockEnumerable=    Matchers.any(HttpMethod.class);
            if(mockEnumerable!= null){
                System.out.println(mockEnumerable.ordinal());
                System.out.println(mockEnumerable.name());

                System.out.println(mockEnumerable.name()+"mocking suceess");
            } else {
               int ordinal;
               //Randomize all possible  value of  enum 
               Random rand = new Random();
               int imatch =  Matchers.anyInt();
               if(  imatch>HttpMethod.values().length)
                 ordinal = 0    ;
               else
                ordinal = rand.nextInt(HttpMethod.values().length);

               // 0-9.  mockEnumerable=
               mockEnumerable= HttpMethod.values()[ordinal];
               System.out.println(mockEnumerable.ordinal());
               System.out.println(mockEnumerable.name());       
            }
       }  
    }
}

Ausgabe :

0
GET
0
GET
5
PATCH
5
PATCH
4
HEAD
5
PATCH
3
DELETE
0
GET
4
HEAD
2
PUT
Jin Thakur
quelle
0

Ich denke, dass der einfachste Weg, um die IllegalArgumentException zu erreichen, darin besteht, null an die foo-Methode zu übergeben, und Sie werden "Weiß nicht, wie man mit null umgeht" lesen.

Steven Kuypers
quelle
2
Dies ist überhaupt nicht hilfreich, da das switchAufgeben eines nullWertes ein ergibt NullPointerExceptionund nicht dem defaultFall folgt (der im Beispiel bis nach dem durchfälltswitch Aussage
Vampire
0

Ich habe meiner Aufzählung eine unbekannte Option hinzugefügt, die ich während des Tests übergebe. Nicht in jedem Fall ideal, aber einfach.

Ryan
quelle
-10

Ich würde den Standardfall mit einem von enum Fällen setzen:

  public static enum MyEnum {A, B}

  public int foo(MyEnum value) {
    if (value == null) throw new IllegalArgumentException("Do not know how to handle " + value);

    switch(value) {
        case(A):
           return calculateSomething();
        case(B):
        default:
           return calculateSomethingElse();
    }
  }
Elioks
quelle
15
Dies ist nicht das gewünschte Verhalten, sondern führt zu unerwarteten Ergebnissen, wenn ein neuer Aufzählungswert hinzugefügt wird.
Fortan