JUnit4 fail() is hier, maar waar is pass()?

Er is een fail()-methode in de JUnit4-bibliotheek. Ik vind het leuk, maar ervaar een gebrek aan de pass()-methode die niet aanwezig is in de bibliotheek. Waarom is het zo?

Ik heb ontdekt dat ik in plaats daarvan assertTrue(true)kan gebruiken, maar het ziet er nog steeds onlogisch uit.

@Test
 public void testSetterForeignWord(){
  try {
   card.setForeignWord("");
   fail();
  } catch (IncorrectArgumentForSetter ex){
  }
 // assertTrue(true);
 }

Antwoord 1, autoriteit 100%

Bel de return-verklaring wanneer uw test is voltooid en geslaagd.


Antwoord 2, autoriteit 88%

Zolang de test geen uitzondering genereert, is deze geslaagd, tenzij uw @Test-annotatie een verwachte uitzondering aangeeft. Ik veronderstel dat een pass()een speciale uitzondering zou kunnen veroorzaken die JUnit altijd interpreteert als geslaagd, om de test te kortsluiten, maar dat zou indruisen tegen het gebruikelijke ontwerp van tests (dwz aannemen dat het gelukt is en alleen faalt als een bewering faalt) en als mensen het idee kregen dat het de voorkeur had om pass()te gebruiken, zou dit een groot aantal slagen voor tests aanzienlijk vertragen (vanwege de overhead van het maken van uitzonderingen). Falende tests zouden niet de norm moeten zijn, dus het is niet erg als ze die overhead hebben.

Houd er rekening mee dat uw voorbeeld als volgt kan worden herschreven:

@Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
  card.setForeignWord("");
}

U moet ook de voorkeur geven aan het gebruik van standaard Java-uitzonderingen. Uw IncorrectArgumentForSetterzou waarschijnlijk een IllegalArgumentExceptionmoeten zijn.


Antwoord 3, autoriteit 9%

Ik denk dat deze vraag een bijgewerkt antwoord nodig heeft, aangezien de meeste antwoorden hier behoorlijk verouderd zijn.

Eerst op de vraag van de OP:

Ik denk dat het redelijk goed wordt geaccepteerd dat het introduceren van het “verwachte uitzondering”-concept in JUnit een slechte zet was, aangezien die uitzondering overal kan worden gemaakt, en het zal de test doorstaan. Het werkt als je zeer domeinspecifieke uitzonderingen gooit (en beweert), maar ik gooi dat soort uitzonderingen alleen als ik aan code werk die absoluut onberispelijk moet zijn, –de meeste API’s gooien gewoon de ingebouwde uitzonderingen zoals IllegalArgumentExceptionof IllegalStateException. Als twee aanroepen die je maakt deze uitzonderingen mogelijk kunnen veroorzaken, dan zal de annotatie @ExpectedExceptionje test groen blokkeren, zelfs als het de verkeerde regel is die de uitzondering veroorzaakt!

Voor deze situatie heb ik een klasse geschreven die ik zeker weet dat vele anderen hier hebben geschreven, dat is een assertThrows-methode:

public class Exceptions {
    private Exceptions(){}
    public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
        try{
            actionThatShouldThrow.run();
            fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
        }
        catch(Exception e){
            if ( ! expectedException.isInstance(e)) {
                throw e;
            }
        }
    }
}

deze methode keert gewoon terug als de uitzondering wordt gegenereerd, zodat u verdere beweringen/verificatie in uw test kunt doen.

met java 8-syntaxis ziet je test er heel mooi uit. Hieronder vindt u een van de eenvoudigere tests op ons model die de methode gebruikt:

@Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
    //setup
    AxisRange range = new AxisRange(0,100);
    //act
    Runnable act = () -> range.setLowerBound(200);
    //assert
    assertThrows(IllegalArgumentException.class, act);
}

deze tests zijn een beetje wankel omdat de stap “act” eigenlijk geen actie uitvoert, maar ik denk dat de betekenis nog steeds redelijk duidelijk is.

er is ook een kleine bibliotheek op maven genaamd catch-exceptiondie de mockito-achtige syntaxis om te controleren of er uitzonderingen worden gegenereerd. Het ziet er mooi uit, maar ik ben geen fan van dynamische proxy’s. Dat gezegd hebbende, de syntaxis is zo glad dat het verleidelijk blijft:

// given: an empty list
List myList = new ArrayList();
// when: we try to get the first element of the list
// then: catch the exception if any is thrown 
catchException(myList).get(1);
// then: we expect an IndexOutOfBoundsException
assert caughtException() instanceof IndexOutOfBoundsException;

Ten slotte, voor de situatie die ik tegenkwam om bij deze thread te komen, is er een manier om tests te negerenals aan een bepaalde voorwaarde is voldaan.

Op dit moment ben ik bezig om een ​​aantal DLL’s te laten aanroepen via een Java native-library-loading-library genaamd JNA, maar onze build-server bevindt zich in ubuntu. Ik probeer dit soort ontwikkeling graag te stimuleren met JUnit-tests – ook al zijn ze op dit moment verre van “eenheden”. Wat ik wil doen is de test uitvoeren als ik op een lokale computer werk, maar de test negeren als we op ubuntu zijn. JUnit 4 heeft hier wel een voorziening voor, genaamd Assume:

@Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
    //this line will cause the test to be branded as "ignored" when "isCircleCI" 
    //(the machine running ubuntu is running this test) is true.
    Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
    //an ignored test will typically result in some qualifier being put on the results, 
    //but will also not typically prevent a green-ton most platforms. 
    //setup
    URL url = DLLTestFixture.class.getResource("USERDLL.dll");
    String path = url.toURI().getPath();
    path = path.substring(0, path.lastIndexOf("/"));
    //act
    NativeLibrary.addSearchPath("USERDLL", path);
    Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);
    //assert
    assertThat(dll).isNotNull();
}

Antwoord 4, autoriteit 5%

Ik was ook op zoek naar een pass-methode voor JUnit, zodat ik enkele tests kon kortsluiten die in sommige scenario’s niet van toepassing waren (er zijn integratietests in plaats van pure unit-tests). Zo jammer dat het er niet is.

Gelukkig is er een manier om een ​​test voorwaardelijk te laten negeren, wat in mijn geval zelfs nog beter past met de assumeTrue-methode:

Assume.assumeTrue(isTestApplicable);

Dus hier wordt de test alleen uitgevoerd als isTestApplicable waar is, anders wordt de test genegeerd.


Antwoord 5, autoriteit 3%

De pass-methode is niet nodig, want als er geen AssertionFailedException wordt gegenereerd vanuit de testcode, zal de unit-testcase slagen.

De methode fail() genereert in feite een AssertionFailedException om de testCase te laten mislukken als de controle op dat punt komt.

Other episodes