Boognish
Boognish

Reputation: 103

JUnit how to handle DateTimeParseException

How can I test for 'bad input' using JUnit? I am trying to instantiate a Flight object by passing the first parameter of it a value that cannot be parsed to type LocalTime. When I do so, the "fail" in the JUnit testConstructor method gives an error. How should I handle this Exception so it can pass the JUnit test without error? Thank you

protected Flight(String scheduledTime, String eventType, String identifier) {
    try {
        this.scheduledTime = LocalTime.parse(scheduledTime);
        this.eventType = EventType.valueOf(eventType);
        this.identifier = identifier;
        this.actualTime = null;
        this.runwayUsed = null;
    }
    catch(Exception e) {
        System.out.println(e + " Flight constructor");
    } 

} //end of constructor

Below in the try/catch block is the JUnit code that is giving the error.

@Test
public void testConstructor() {

    Flight f1 = new Flight("00:00", "ARRIVAL", "A001");
    Flight f2 = new Flight("00:00", "DEPARTURE", "D001");

    assertEquals(LocalTime.parse("00:00"), f1.getScheduledTime());
    assertEquals(EventType.ARRIVAL, f1.getEvent());
    assertEquals("A001", f1.getIdent());
    assertEquals(null, f1.getActualTime());
    assertEquals(null, f1.getRunwayUsed());

    assertEquals(LocalTime.parse("00:00"), f2.getScheduledTime());
    assertEquals(EventType.DEPARTURE, f2.getEvent());
    assertEquals("D001", f2.getIdent());
    assertEquals(null, f2.getActualTime());
    assertEquals(null, f2.getRunwayUsed());

    //invalid entry for scheduledTime
    try {
        Flight f3 = new Flight("00:0j", "ARRIVAL", "A001");
        fail("Expected exception");
    } //end of try
    catch(Exception e) {
        System.out.println(e);
    } //end of catch

} 

Upvotes: 0

Views: 1460

Answers (4)

Thiago Procaci
Thiago Procaci

Reputation: 1523

You have some options.

The first one is to catch the exception in the constructor method. In this scenario, you should adapt your test method. So, the constructor would be something like:

protected Flight(String scheduledTime, String eventType, String identifier) {
        this.identifier = identifier;
        this.actualTime = null;
        this.runwayUsed = null;    
    try {
            this.scheduledTime = LocalTime.parse(scheduledTime);
        } catch(Exception e) {
            System.out.println(e + " Flight constructor - scheduledTime problem");
        } 
    try {
             this.eventType = EventType.valueOf(eventType);
        } catch(Exception e) {
            System.out.println(e + " Flight constructor - eventType problem");
        }
}

Consequently, your test should be:

@Test
public void testConstructor() {
    Flight f = new Flight("00:0j", "ARRIVAL", "A001");
    assertNull(f.scheduledTime);
    assertEquals("A001", f.identifier); 
    // other asserts
}

The second option is to throw the exception if something goes wrong in the constructor. In this case, the constructor would be like:

protected Flight(String scheduledTime, String eventType, String identifier) {
    this.identifier = identifier;
        this.actualTime = null;
        this.runwayUsed = null;    
        this.scheduledTime = LocalTime.parse(scheduledTime);
        this.eventType = EventType.valueOf(eventType);      
}

And your test could be like:

 @Test
   public void testConstructor() {

    try {
          new Flight("00:0j", "ARRIVAL", "A001");
          fail("Expected exception");
    } catch(Exception e) {
           assertNotNull(e);
        } 
}

or

@Test(expected = Exception.class) // You can also specialize this exception to DateTimeParseException or any other
public void testConstructor() { 
     new Flight("00:0j", "ARRIVAL", "A001");

}

As you see, you have several options.

Upvotes: 0

chess4ever
chess4ever

Reputation: 124

What you are doing is correct, but maybe it would be clearer if you were using Junit 4 you can specify the exception that you expect in the @Test annotation, see here for details.

If the test fails it's because your Flight constructor is not throwing any exception.

Upvotes: 0

Jamie Bisotti
Jamie Bisotti

Reputation: 2685

Don't catch Exception in the constructor.

protected Flight(final String scheduledTime,
                 final String eventType,
                 final String identifier) {

    this.scheduledTime = LocalTime.parse(scheduledTime);
    this.eventType = EventType.valueOf(eventType);
    this.identifier = identifier;
    this.actualTime = null;
    this.runwayUsed = null;
}

A better design might be to change the constructor to this:

protected Flight(final LocalTime scheduledTime,
                 final EventType eventType,
                 final String identifier) {
    ...
}

Also, I'd suggest your single test be broken up into three separate, well-named, tests.

Good luck.

Upvotes: 1

Ivan
Ivan

Reputation: 8758

First, as pointed out by @binoternary your constructor doesn't throw exception outside of itself it just logs it instead. Second, to make your test pass only if specific exception is thrown then you need to add this annotation to the test method:

@Test(expected = DateTimeParseException.class) // or any other exception class expected to be thrown
public void testException() {
    Flight f3 = new Flight("00:0j", "ARRIVAL", "A001");
}

Upvotes: 1

Related Questions