2013-12-16 7 views
9

Ich habe eine gut spezifizierte Schnittstelle und gegen, dass ich meine JUnit-Tests schreiben:Kann ich mehrere ausgelöste Ausnahmen in einer Testmethode testen?

public interface ShortMessageService { 

    /** 
    * Creates a message. A message is related to a topic 
    * Creates a date for the message 
    * @throws IllegalArgumentException, if the message is longer then 255 characters. 
    * @throws IllegalArgumentException, if the message ist shorter then 10 characters. 
    * @throws IllegalArgumentException, if the user doesn't exist 
    * @throws IllegalArgumentException, if the topic doesn't exist 
    * @throws NullPointerException, if one argument is null. 
    * @param userName 
    * @param message 
    * @return ID of the new created message 
    */ 
    Long createMessage(String userName, String message, String topic); 

[...] 

} 

Wie Sie die Implementierung verschiedene Ausnahmen auslösen kann, für die wir haben Tests schreiben sehen können. Mein aktueller Ansatz ist ein Testverfahren für eine mögliche Ausnahme in der Schnittstelle wie folgt angegeben zu schreiben:

public abstract class AbstractShortMessageServiceTest 
{ 

    String message; 
    String username; 
    String topic; 

    /** 
    * @return A new empty instance of an implementation of ShortMessageService. 
    */ 
    protected abstract ShortMessageService getNewShortMessageService(); 

    private ShortMessageService messageService; 

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

    @Before 
    public void setUp() throws Exception 
    { 
     messageService = getNewShortMessageService(); 
     message = "Test Message"; 
     username = "TestUser"; 
     topic = "TestTopic"; 
    } 

    @Test 
    public void testCreateMessage() 
    { 
     assertEquals(new Long(1L), messageService.createMessage(username, message, topic)); 
    } 

    @Test (expected = IllegalArgumentException.class) 
    public void testCreateMessageUserMissing() throws Exception 
    { 
     messageService.createMessage("", message, topic); 
    } 

    @Test (expected = IllegalArgumentException.class) 
    public void testCreateMessageTopicMissing() throws Exception 
    { 
     messageService.createMessage(username, message, ""); 
    } 

    @Test (expected = IllegalArgumentException.class) 
    public void testCreateMessageTooLong() throws Exception 
    { 
     String message = ""; 
     for (int i=0; i<255; i++) { 
      message += "a"; 
     } 
     messageService.createMessage(username, message, topic); 
    } 


    @Test (expected = IllegalArgumentException.class) 
    public void testCreateMessageTooShort() throws Exception 
    { 
     messageService.createMessage(username, "", topic); 
    } 

    @Test (expected = NullPointerException.class) 
    public void testCreateMessageNull() throws Exception 
    { 
     messageService.createMessage(username, null, topic); 
    } 

[...] 

} 

So jetzt habe ich viele Prüfverfahren definieren muß, um für diese eine Methode in der Schnittstelle definiert und das fühlt sich peinlich. Kann ich alle diese Ausnahmetests in einer Testmethode kombinieren oder was ist die beste Vorgehensweise?

Antwort

4

Leider haben die @Test Anmerkung erlauben nicht für mehrere Ausnahmetypen (api Referenz http://junit.sourceforge.net/javadoc/org/junit/Test.html) zu kontrollieren.

Als erste Option würde ich befürworten, zu TestNG zu wechseln. Wenn Ihr Team das nicht erlaubt, gibt es nur wenige Dinge, die Sie in JUnit tun können.

Verwenden Sie unbedingt parametrisierte Testfälle, damit Sie pro Testfall keine Testfunktion schreiben müssen (http://junit.sourceforge.net/javadoc/org/junit/runners/Parameterized.html). Von hier aus gibt es ein paar Optionen.

  1. Gruppieren Sie Ihre Testdaten nach Ausnahmetypen.

    @Test (expected = IllegalArgumentException.class) 
    public void testIllegalArgumentException(String username, String message, String topic) {} 
    
    @Test (expected = NullPointerException.class) 
    public void testNullPointerException(String username, String message, String topic) {} 
    
  2. Kombinieren Sie die Ausnahmetypen in Ihrer Methodensignatur. (Dies ist, was ich empfehlen) Raue Umriss unten ...

    public void testException(String username, String message, String topic, Class<? extends Exception>[] expectedExceptionClasses) { 
        try { 
         // exception throwing code 
        } catch (Exception e) { 
         boolean found = false; 
         for (Class<?> expectedException : expectedExceptions) { 
          if (e instanceof expectedException) { 
           found = true; 
          } 
         } 
         if (found) { 
          return; 
         } 
        } 
        Assert.fail(); 
    } 
    
  3. Setzen Sie alle Tests unter dem Dach Ausnahmeklasse (ich habe das Gefühl, Sie wollen nicht, das zu tun.).

    @Test (expected = Exception.class) 
    public void testException(String username, String message, String topic) {} 
    
+1

Das ist gut, aber man kann dies die ExpectedException Regel verbessern: https://github.com/junit-team/junit/blob/master/src/main/java/org/junit /rules/ExpectedException.java –

0

Es könnte nicht die beste Idee sein, sie alle in einer Methode zu kombinieren, da Sie nicht wirklich wissen würden, welcher Testfall welche Ausnahme ausgelöst hat.

Zum Beispiel, wenn Sie die Zeile hatte

messageService.createMessage(username, null, topic); 

die eine NullPointerException werfen sollte, sondern warf es einen IllegalArgumentException, Sie wollen nicht, dass als Erfolg zu zählen.

Wenn Sie alle Ausnahmen dieser Methode in einem Testfall testen möchten, wäre es eine gute Alternative, jeden Ausnahmetest in einen try..catch-Block zu verpacken.

Zum Beispiel könnten Sie

@Test 
public void testCreateMessageExceptions() { 
    // test #1: a null message 
    try { 
     messageService.createMessage(username, null, topic); 
     // if it got this far, that's a problem! 
     fail(); 
    } catch(NullPointerException e) { 
     // great, that's what it's meant to do! continue testing 
    } catch(Exception e) { 
     // if it threw the wrong type of exception, that's a problem! 
     fail(); 
    } 

    // test #2: an empty user 
    try { 
     messageService.createMessage("", message, topic); 
     fail(); 
    } catch(IllegalArgumentException e) { 

    } catch(Exception e) { 
     fail(); 
    } 

    // ... 
} 
Verwandte Themen