Reputation: 103
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
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
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
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
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