JUnit how to handle DateTimeParseException - java

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
}

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");
}

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.

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.

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.

Related

Using reflection to identify if the error thrown matches expected error

I need to write a simple code tester program, but I got stuck comparing the given error class with the test expected class. I am supposed to use reflection in this exercise.
I have my code testing class:
public class TestRunner {
private String result = "";
public void runTests(List<String> testClassNames) {
for (String testClassName : testClassNames) {
Class<?> clazz;
try {
clazz = Class.forName(testClassName);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("No such class.");
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getAnnotation(MyTest.class) != null) {
if (testClassName.equals("reflection.tester.ExampleTests1")) {
result += method.getName() + "() - ";
ExampleTests1 instance = new ExampleTests1();
try {
// if null, result = OK
method.invoke(instance);
result += "OK\n";
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
// if error is caught result = FAILED
result += "FAILED\n";
}
} else {
// the second class. should only return "OK" if the error is implemented from the exception class
result += method.getName() + "() - ";
ExampleTests2 instance = new ExampleTests2();
try {
method.invoke(instance);
result += "FAILED\n";
} catch (RuntimeException e) {
Throwable original = e.getCause();
Object expected = method.getReturnType();
if (original.getClass().isAssignableFrom(expected.getClass())) {
result += "OK\n";
} else {
result += "FAILED\n";
}
} catch (InvocationTargetException | IllegalAccessException e) {
result += "ERROR\n";
}
}
}
}
}
}
}
Also have two test classes. In the first one there is only one rule, if the test won't throw an exception the test should pass, and it is working. The second class is more complicated. If the thrown error class is implemented or same to the expected error class then the test should pass and OK should be added to the result. Currently my code won't catch RunTimeException at all and moves to the last catch block. How can I fix this?
I will also add the test class for more information.
public class ExampleTests2 {
#MyTest(expected = RuntimeException.class)
public void test3() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test4() {
throw new RuntimeException();
}
#MyTest(expected = IllegalStateException.class)
public void test5() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test6() {
}
public void helperMethod() {
}
}
test3() and test5() should pass, test4() and test6() should fail, helperMethod() won't be checked because I only need to use the tests with #MyTest annotation.
JUnit has an assertThrows method that checks that an Exception is thrown. It has a method signature of
static <T extends Throwable> assertThrows​(Class<T> expectedType, Executable executable){}
Here's the documentation: https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html#assertThrows(java.lang.Class,org.junit.jupiter.api.function.Executable)
and here's how JUnit implements it:
https://github.com/junit-team/junit5/blob/main/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java

Why is mocking static method with Mockito not working in my case?

I have this complicated method. I want to mock just the result. All what is inside should basically be ignored. I am using Mockito .
class JiraManager
{
public static List<Issue> searchMitarbeiterIssue(String mitarbeiterName) throws JqlParseException, SearchException {
ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
JqlQueryParser jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class);
SearchService searchService = ComponentAccessor.getComponent(SearchService.class);
String jqlSearchString = "project = BLUB AND issuetype = BLOB AND text ~ \"" + myName+ "\""+" AND status = aktive";
final Query query = jqlQueryParser.parseQuery(jqlSearchString);
List<Issue> issues = null;
Query queryToExecute = JqlQueryBuilder.newBuilder(query).buildQuery();
// get results for the jql query
SearchResults searchResult = searchService.search(user, queryToExecute, PagerFilter.getUnlimitedFilter());
try {
Method newGetMethod = null;
try {
newGetMethod = SearchResults.class.getMethod("getIssues");
} catch (NoSuchMethodException e) {
try {
LOGGER.warn("SearchResults.getIssues does not exist - trying to use getResults!");
newGetMethod = SearchResults.class.getMethod("getResults");
} catch (NoSuchMethodError e2) {
LOGGER.error("SearchResults.getResults does not exist!");
}
}
if (newGetMethod != null) {
issues = (List<Issue>) newGetMethod.invoke(searchResult);
} else {
LOGGER.error("ERROR NO METHOD TO GET ISSUES !");
throw new RuntimeException("ICT: SearchResults Service from JIRA NOT AVAILABLE (getIssue / getResults)");
}
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOGGER.error("Jql Helper can not get search result (ICT)", e);
} catch (Exception e) {
LOGGER.error("Jql Helper can not get search result - other exception (ICT)", e);
}
return issues;
}
}
I do not want Mockito to run all the Code inside the method. It should just return the List . That's all . So I tried this:
try (MockedStatic<JiraManager> utilities = Mockito.mockStatic(JiraManager.class)) {
utilities.when(() -> JiraManager.searchMitarbeiterIssue(any()))
.thenReturn(Collections.singletonList(mitarbeiterIssueResult));
assertTrue(JiraManager.searchMitarbeiterIssue("").size() == 1);
}
But it is not working. It always returns null. Why ?? Is the code inside the method executed ? What is Mockito exactly doing ?
Below works for me.
Create MockedStatic class field
private MockedStatic<MyUtilClassWithStaticMethods> myUtil;
Initialise MockedStatic before each test case
#BeforeEach
void initialiseWorker() {
myUtil = mockStatic(MyUtilClassWithStaticMethods.class);
}
Close MockedStatic after each test case
#AfterEach
public void close() {
myUtil.close();
}
Mock static method behaviour in test case
#Test
void test() {
when(MyUtilClassWithStaticMethods.staticMethod(any())).thenReturn(null);
}
You can return list instead of null here.

JUnit: Test for class method breaks compilation when class tested does not contain method

Building a JUnit test class. It is being used as an autograder. Some of the submissions do not have all of the required class methods (even though it was part of specs). Autograder is of course only a part of the total grade (say 50%). It improves the issue of playing 500 games, to test whether they function as expected.
In addition to checking whether all methods exist, it would be nice to check if they are also callable.
JUnit test code snippet:
#Test
public void test_1p1t4_15() {
// Test if callable
try {
Direction d1 = new Direction();
checkMethod(d1.getClass(), "print");
} catch (Exception e) {
fail("Test fails:"+e.toString());
}
}
A checkMethod function helps show when issues are related to implementation of the method, such as visibility, e.g.
public void checkMethod( Class cls, String fnName) {
// Checks method validity for methods not including an argument
try {
Method m = cls.getMethod(fnName);
assertNotNull(m);
} catch (Exception e) {
fail("Failed: "+e.toString());
}
}
public void checkMethod( Class cls, String fnName, Class type) {
// Checks method validity for methods including an argument
try {
Method m = cls.getMethod(fnName, type);
assertNotNull(m);
} catch (Exception e) {
fail("Failed: "+e.toString());
}
}
public void testMethod( Class cls, String fnName) {
// Code here
}
public void testMethod( Class cls, String fnName, argType, argValue) {
// Code here
// Including an argument
}
This is a simple example that demonstrates how to find and invoke a method with arguments, if the method exists. You will want to call invokeIfExists in your JUnit tests. You will then be able to assert that the returned value matches whatever you expect.
import java.lang.reflect.*;
public class Main {
static Object invokeIfExists(Class<?> cls, String methodName,
Class<?>[] argTypes,
Object callingObject, Object[] args) {
try {
Method method = cls.getDeclaredMethod(methodName, argTypes);
return method.invoke(callingObject, args);
} catch (SecurityException | NoSuchMethodException e) {
System.err.println("Method " + methodName + " not found.");
} catch (IllegalAccessException | IllegalArgumentException e) {
System.err.println("Method " + methodName + " could not be invoked.");
} catch (InvocationTargetException e) {
System.err.println("Method " + methodName + " threw an exception.");
}
return null; // Or assert false, etc.
}
public static void main(String[] args) {
Direction direction = new Direction("a", "b");
// Tries to invoke "direction.print(123)"
String printResult = (String) invokeIfExists(
Direction.class, "print", new Class<?>[]{int.class},
direction, new Object[]{123});
System.out.println(printResult); // "Direction: a -> b and foo=123"
// Tries to invoke "direction.doesntExist()"
Object doesntExistResult = invokeIfExists(
Direction.class, "doesntExist", new Class<?>[]{},
direction, new Object[]{});
System.out.println(doesntExistResult); // null
}
}
class Direction {
private String from, to;
Direction(String from, String to) {
this.from = from;
this.to = to;
}
String print(int foo) {
return "Direction: " + from + " -> " + to + " and foo=" + foo;
}
}

Testing a method that reads and processes data from a file [duplicate]

This question already has answers here:
Mocking Files in Java - Mock Contents - Mockito
(3 answers)
Closed 6 years ago.
I have the following code:
public class FolderServiceImpl implements FolderService {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
if (folderStatusFile.exists()) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(folderStatusFile));
String line = br.readLine();
status = Integer.parseInt(line);
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
L.warn("could not close reader ", e);
}
}
}
} else {
status = 3;
}
return status;
}
}
I want to test this method without creating actual files for every case. I should be using Java 1.7, JUnit 4, Mockito and/or PowerMockito.
Any ideas on how to do that?
I am talking about mocking either the data source or simply changeing the input for the method.
My test looks something like this:
`#Rule
public TemporaryFolder folder = new TemporaryFolder();
private FolderServiceImpl serviceToTest = new FolderServiceImpl();
private String folderPath;
#Before
public void setUp() {
folderPath = folder.getRoot().getAbsolutePath();
try {
folder.newFile(".folderstatus");
} catch (IOException e) {
e.printStackTrace();
}
}
#Test
public void shouldReturnFolderStatus3WhenFolderStatusIsNotFound() {
// given
deleteFolderStatusFile();
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(3, status);
}
#Test
public void shouldReturnFolderStatus4WhenTheStatusIsUnreadable() {
// given
writeStatusToTestFile("Test");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(4, status);
}
#Test
public void shouldReturnFolderStatusInTheFile() {
// given
writeStatusToTestFile("1");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(1, status);
}
private void writeStatusToTestFile(String status) {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.write(file, status.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
private void deleteFolderStatusFile() {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.delete(file);
} catch (IOException e) {
e.printStackTrace();
}
}`
Although the answer of #BenHeid may work I'd suggest to change to different approach.
IMHO when ever I use PowerMock(-ito) it is a surrender to bad design.
Also the PowerMock solution will confuse test coverage tools since it changes the Applications byte code after it has been instrumented for coverage measurement.
So the approach I'd prefer is to stick to Clean Code and OOP rules.
One of them is separation of concerns.
In your case the method creates some infrastructure classes (dependencies) to work with, namely FileReader and BufferedReader.
But the instantiation of (direct) dependencies is not a responsibility of a class containing business logic.
Therefore I'd suggest to refactor that code out into a separate class:
class ReaderFactory {
public BufferedReader createFor(File file) throws FileNotFoundException {
return new BufferedReader(new FileReader(file));
}
}
Your Class would change to this:
class FolderServiceImpl {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
private final ReaderFactory readerFactory;
FolderServiceImpl(ReaderFactory readerFactory) {
this.readerFactory = readerFactory;
}
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
// try "with resource" takes care of closing the reader
try (BufferedReader br = readerFactory.createFor(folderStatusFile);) {
String line = br.readLine();
status = Integer.parseInt(line);
} catch (IOException e) {
status = 3;
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
}
return status;
}
}
And your Test would be this:
public class FolderServiceImplTest {
private static final String ANY_FILE_NAME = "";
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Rule
public ExpectedException thrown = ExpectedException.none();
#Mock
private ReaderFactory readerFactory;
#InjectMocks
FolderServiceImpl sut;
#Test
public void getStatus_FileNotExisting_returnStatus3() throws Exception {
// arrange
Mockito.doThrow(new FileNotFoundException("UnitTest")).when(readerFactory).createFor(Mockito.any(File.class));
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(3));
}
#Test
public void getStatus_ValidFile_returnFileContentAsInt() throws Exception {
// arrange
BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
Mockito.doReturn(bufferedReader).when(readerFactory).createFor(Mockito.any(File.class));
Mockito.doReturn("4711").when(bufferedReader).readLine();
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(4711));
}
}
You have to use something like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(tests.class)
public class test {
#Test
public void test() throws Exception {
File fileMock = Mockito.mock(File.class);
PowerMockito.whenNew(File.class).withArguments(Mockito.anyString(), Mockito.anyString()).thenReturn(fileMock);
FolderServiceImpl sut = new FolderServiceImpl sut ();
Mockito.when(fileMock.exists()).thenReturn(true);
sut.getStatus("");
// Your verifications..
}
}
Powermock will mock the File object which is created in the method getStatus of your class. With Mockito.when you can say what is the return value of folderStatusFile.exists() in your code.
EDIT
I have included the following two jars with maven, but you don't need to use maven: https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4/1.4.6 and https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito/1.4.9 and https://mvnrepository.com/artifact/org.mockito/mockito-all/1.10.19

Junit test case for 'if' condition in code

I am getting null pointer exception at if condition in the below method.Here is my method and junit test class i am working.
METHOD
#Override
public Event getDisplayEventDetails(String ceccid,
String ceocid) {
Event evnt = null;
if(!(validate.isStringBlank(ceccid)))
{
if(!(validate.isStringBlank(ceocid)))
{
String dispEventUri = eventServicesUrl;
eventSrvcLogger.debug("dispEventUri..."+dispEventUri);
try {
ResponseEntity<Event> responseEntity = restTemplate.getForEntity(dispEventUri , Event.class);
evnt=responseEntity.getBody();
if(responseEntity.getStatusCode().toString().equals("200")){
if(evnt.getValue().length > 0){
for(int i=0;i<evnt.getValue().length;i++){
DisplayValue val = new DisplayValue();
val = evnt.getValue()[i];
eventSrvcLogger.debug(val.toString());
}
} else{
evnt.setStatusCode(responseEntity.getStatusCode().toString());
evnt.setStatus(Boolean.FALSE);
evnt.setMessage("Exception occured in handling the request BAD REQUEST");
}
}
} catch (RestClientException e) {
eventSrvcLogger.error("DisplayEventServiceImpl displayEventDetail() RestClientException",
e);
}
}
}
return evnt;
}
Junit class
#Test
public void testGetDisplayEventDetails() throws Exception{
//test setup with mocking, expectations, data population
String eventServicesUrl = "http://restUrl";
Event evnt = newEvent();
ResponseEntity<Event> responseEntity = new ResponseEntity<Event>(evnt, HttpStatus.OK);
DisplayValue[] dv = new DisplayValue[1];
DisplayValue dvalue = new DisplayValue();
dvalue.setFirst_name("Ron");
dv[0] =dvalue;
evnt.setValue(dv);
new NonStrictExpectations() {
{
restTemplate.getForEntity(anyString,evnt.class );returns(responseEntity);
}
};
EventService evntSrvcImpl = new EventServiceImpl();
ReflectionTestUtils.setField(evntSrvcImpl,"eventServicesUrl", eventServicesUrl);
ReflectionTestUtils.setField(evntSrvcImpl,"restTemplate", restTemplate);
}
//execute your test case
Event evnt1 = evntSrvcImpl.getDisplayEventDetails("ceccid", "ceocid");
//perform verifications and assertions
assertNotNull(evnt);
assertEquals(evnt.getValue()[0].getName(), evnt1.getValue()[0].getName());
}
On debugging its throwing null pointer exception
at this line of code
if(responseEntity.getStatusCode().toString().equals("200"))
How to set that value in the junit test class ?
I got it by adding below lines to junit test class:
HttpStatus statusCode= HttpStatus.OK;,
responseEntity.getStatusCode(); returns(statusCode);

Categories