I define a custom exception like so :
package source.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ValidationException extends Exception
{
private static final Logger logger = LoggerFactory.getLogger("source.exception.ValidationException");
public ValidationException(String message)
{
super(message);
ValidationException e = new ValidationException();
logger.error("Exception : {}" , e);
}
}
In the main program I use this exception like so :
public void readFile(String path) throws ValidationException
{
logger.debug("Input file path = {}" , path);
try
{
if(validatePath(path))
{
mathExpressionReader = new BufferedReader(new FileReader(path));
}
else
{
throw new ValidationException("Your file dose not exist!");
}
}
catch(Exception ex)
{
logger.error("Exception {} has occurred" , ex);
}
}
Now I don't know how to print stack trace when validatePath fail(means if statement become false) .Can anyone help me to print stack trace in custom exception?
Why not just using e.printStackTrace()?
public class ValidationException extends Exception
{
public ValidationException(String message)
{
super(message);
}
}
public void readFile(String path) throws ValidationException
{
logger.debug("Input file path = {}" , path);
try
{
if(validatePath(path))
{
mathExpressionReader = new BufferedReader(new FileReader(path));
}
else
{
throw new ValidationException("Your file dose not exist!");
}
} catch (ValidationException e) {
// This will print the stack trace.
e.printStackTrace();
}
}
Related
I am trying to test exception handling when using Opencsv's CSVReader. The data will be coming from a String.
It's not working because I am (probably) not properly mocking the CSVReader, but cannot quite figure out what I need to do.
Here's the class
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvValidationException;
// other imports skipped
public class MyCsvReader {
private Path contentsAsString;
private CSVReader csvReader;
public MyCsvReader(final String contentsAsString) {
InputStream inputStream = new ByteArrayInputStream(contentsAsString.getBytes());
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
csvReader = new CSVReaderBuilder(inputStreamReader)
.withSkipLines(0)
.withKeepCarriageReturn(false)
.build();
}
public void readData() {
String[] line;
try {
while ((line = csvReader.readNext()) != null) {
System.out.println("line:" + Arrays.toString(line));
}
} catch (IOException e) {
System.out.println("got IOException");
// I will be throwing a custom exception here
throw new RuntimeException(e);
} catch (CsvValidationException e) {
System.out.println("got CsvValidationException");
// and a different custom exception here
throw new RuntimeException(e);
}
}
}
and the test
public class MyCsvReaderTest {
#Test
public void testException() throws Exception {
String[] rows = {
"column1,column2,column3",
"test,abc,def"
};
String rowData = String.join("\n", rows);
CSVReader mock = Mockito.mock(CSVReader.class);
Mockito.when(mock.readNext()).thenThrow(new IOException("test"));
MyCsvReader reader = new MyCsvReader(rowData);
try {
reader.readData();
fail("Expected an exception, but call succeeded");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
When I run it, reader.readNext() does not throw an exception
line: [column1, column2, column3]
line: [test, abc, def]
org.opentest4j.AssertionFailedError: Expected and exception, but call succeeded
... stack trace deleted
Suggestions on what I need to do? Thanks!
You don't use a mocked instance but a real one.
If the goal here is throw an exception when mock.readNext() happens you have to do something like this in order to inject your mocked instance of CSVReader:
public class MyCsvReader {
private final CSVReader csvReader;
public MyCsvReader(final CSVReader csvReader) {
this.csvReader = csvReader;
}
public MyCsvReader(final String contentsAsString) {
this(getCsvReader(contentsAsString));
}
private static CSVReader getCsvReader(final String contentsAsString) {
InputStream inputStream = new ByteArrayInputStream(contentsAsString.getBytes());
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
return new CSVReaderBuilder(inputStreamReader)
.withSkipLines(0)
.withKeepCarriageReturn(false)
.build();
}
public void readData() {
String[] line;
try {
while ((line = csvReader.readNext()) != null) {
System.out.println("line:" + Arrays.toString(line));
}
} catch (IOException e) {
System.out.println("got IOException");
// I will be throwing a custom exception here
throw new RuntimeException(e);
} catch (CsvValidationException e) {
System.out.println("got CsvValidationException");
// and a different custom exception here
throw new RuntimeException(e);
}
}
}
public class MyCsvReaderTest {
#Test
public void testException() throws Exception {
CSVReader mock = Mockito.mock(CSVReader.class);
Mockito.when(mock.readNext()).thenThrow(new IOException("test"));
MyCsvReader reader = new MyCsvReader(mock);
try {
reader.readData();
fail("Expected an exception, but call succeeded");
} catch (RuntimeException ignored) {
}
}
}
Problem: if the path to the file was not specified in the arguments, then it still displays the phrase "The file was closed". This works 2 times. In uploadToFile and read method. I pass one path in the arguments, and the second is written in the DownloadFile
public class Task implements AutoCloseable {
public static void main(String[] args) throws IOException {
String DownloadFile = "C:\\Users\\VGilenko\\IdeaProjects\\Task\\src\\main\\resources\\Out.txt";
Map<String, Departament> departments = new HashMap<>();
String path = args.length > 0 ? args[0] : null;
read(path, departments);
transferToDepartment(departments, DownloadFile);
}
private static void uploadToFile(List download, String path) {
int i = 0;
try (FileWriter writer = new FileWriter(path, false)) {
...
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
} finally {
System.out.println("The file was closed");
}
}
public static void transferToDepartment(Map<String, Departament> departments, String downloadFile) {
List<String> download = new ArrayList<>();
...
}
uploadToFile(download, downloadFile);
}
public static void read(String path, Map<String, Departament> departments) throws IOException {
assert path != null;
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path), "CP1251")); br) {
.....
}
}
} catch (FileNotFoundException e) {
System.out.println("The file was not found, check the path");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Correct the file path, step out of the array");
} catch (NullPointerException e) {
System.out.println("You forgot to register the path to the file");
} finally {
System.out.println("The file was closed");
}
}
#Override
public void close() {
System.out.println("The file was closed");
}
}
You have your printout "The file was closed" in your finally statement. If you don't specify a file, you will catch an Exception, and your finally block will be executed.
An easy fix would be to check for the existence of the path (not being empty, not being null).
I have this bit of code which depends from a custom Exception thrown by a function inside findID() it throws a NoClientFound Exception that I made whenever this mentioned function returns a null (The client does not exist).
The IDE suggests that I shall apply that Exception into the code, but in this bit of code, where I need the ID to be null (unique IDs) I "can't catch that exception" since if I catch it, the function will not be executed as intended.
Question: How I can manage this?
Function with the Exception problem
public boolean add(Client c) {
StringBuilder sb = new StringBuilder();
boolean added = false;
try {
if (findID(c.getID()) == null) {
try (BufferedWriter bw = new BufferedWriter(
new FileWriter(fitxer, true));) {
//Add client to file
bw.write(sb.append(c.getID()).append(SEPARADOR).
append(c.getName()).toString());
bw.newLine();//New line
bw.flush(); //Push to file
added = true;
} catch (IOException e) {
Logger.getLogger(DaoClient.class.getName()).log(Level.SEVERE,
null, "Error appeding data to file" + e);
}
}
} catch (IOException ex) {
Logger.getLogger(DaoClient.class.getName()).log(Level.SEVERE, null,
"Error appeding data to file" + ex);
} finally {
}
return addded;
}
Exception Code
public class NoClientFound extends Exception {
private String msg;
public NoClientFound() {
super();
}
public NoClientFound(String msg) {
super(msg);
this.msg = msg;
}
#Override
public String toString() {
return msg;
}
You can catch that exception and handle it accordingly. When you catch NoClientFound exception that means findID(c.getID()) is null. So without handling that in the if block you can handle that within the catch block.
public boolean add(Client c) {
StringBuilder sb = new StringBuilder();
boolean added = false;
try {
// call the function
findID(c.getID());
} catch (NoClientFound ex) {
//handle the NoClientFound exception as you like here
BufferedWriter bw = new BufferedWriter(
new FileWriter(fitxer, true));
//Add client to file
bw.write(sb.append(c.getID()).append(SEPARADOR).
append(c.getName()).toString());
bw.newLine();//New line
bw.flush(); //Push to file
added = true;
}catch (IOException ex) {
Logger.getLogger(DaoClient.class.getName()).log(Level.SEVERE, null,
"Error appeding data to file" + ex);
}finally {
}
return addded;
}
I assume you already have a null check on findID(...)
if( c == null || findID(c.getID()) == null){
throw new NoClientFound("Client not found!");
}else{
//add your file writing operation
}
and Also in NoClientFound class extend it from RuntimeException, not the Exception.
public class NoClientFound extends RuntimeException {
...
}
Caller method:
public void caller(){
Client client = new Client();
client.setId(1);
...
try{
add(client);
}catch(NoClientFound ex){
//client not found then create one for ex...
}
catch(Exception ex){
//somthing else happend
log.error(ex.getmessge());
}
}
I am trying to throw a custom exception
class NumberFormatException extends Exception
{
public NumberFormatException() {}
//Constructor that accepts a message
public NumberFormatException(String message)
{
super(message);
}
}
Later, I am throwing this exception using
throw new NumberFormatException("Exception found");
and later on catching it using
catch(NumberFormatException e)
{
System.out.println(e);
}
It prints something like
NumberFormatException: Exception found
Is it possible to print something like:
java.lang.NumberFormatException: Exception found
The constraint is the catch code can't be modified i.e
catch(NumberFormatException e)
{
System.out.println(e);
}
You are trying to get Canonical name of exception class and here is how you can get it:
catch(NumberFormatException e)
{
System.out.println(e.getClass().getCanonicalName());
}
Refer javadoc for more : getCanonicalName
Override toString In your NumberFormatException class :
class MyException extends Exception{
String message;
public MyException(String string) {
this.message = string;
}
#Override
public String toString() {
String s = getClass().getCanonicalName();
String message = this.message;
return (message != null) ? (s + ": " + message) : s;
}
}
Source : Throwable
Here is a full code testing the method :
package first;
class MyException extends Exception{
String message;
public MyException(String string) {
this.message = string;
}
#Override
public String toString() {
String s = getClass().getCanonicalName();
String message = this.message;
return (message != null) ? (s + ": " + message) : s;
}
}
public class TestingMyException{
public static void main(String[] args) {
try{
throw new MyException("This works !");
}catch(MyException e){
System.out.println(e);
}
}
}
Output
first.MyException: This works !
Since my class is defined in the package named first of my root, the result prints first.MyException.
So you also have to check if your class is not defined in the default package. Otherwise, you'll not get anything but :
MyException: This works !
I want to write unit tests for a parser and would like to check that it correctly throws an exception for all input strings in a list. Now as I understand it, the standard approach with JUnit would be to write a separate test method for each case:
public final class ParseFailureTest1 {
#Test(expected = ParseException.class)
public void testParseFailure1() throws Exception {
Parser.parse("[1 2]"); // Missing comma
}
#Test(expected = ParseException.class)
public void testParseFailure2() throws Exception {
Parser.parse("[1, 2,]"); // Additional commas
}
}
But as I want to apply the same test to 20 or 50 different strings, it seems impractical.
An alternative would be to explicitly check for an exception with a catch block:
public final class ParseFailureTest2 {
#Test
public void testParseFailure() throws Exception {
List<String> documents = Arrays.asList(
"[1 2]", // Missing comma
"[1, 2,]"); // Additional commas
for (String document : documents) {
try {
Parser.parse(document);
throw new AssertionError("Exception was not thrown");
} catch (ParseException e) {
// Expected, do nothing.
}
}
}
}
But this is error prone and I won't get any information about which exception was expected and if a different exception was thrown, it would count as a test error and not a failure.
My solution would be to use a method similar to expectException below:
public final class ParseFailureTest3 {
#Test
public void testParseFailure() throws Exception {
List<String> documents = Arrays.asList(
"[1 2]", // Missing comma
"[1, 2,]"); // Additional commas
for (final String document : documents) {
expectException(ParseException.class, new TestRunnable() {
#Override
public void run() throws Throwable {
Parser.parse(document);
}
});
}
}
public static void expectException(Class<? extends Throwable> expected, TestRunnable test) {
try {
test.run();
} catch (Throwable e) {
if (e.getClass() == expected) {
return; // Expected, do nothing.
} else {
throw new AssertionError(String.format("Wrong exception was thrown: %s instead of %s", e.getClass(), expected), e);
}
}
throw new AssertionError(String.format("Expected exception was not thrown: %s", expected));
}
public interface TestRunnable {
void run() throws Throwable;
}
}
Is there a method for that purpose in the JUnit framework or a related library or would you suggest a different approach (or one of my rejected approaches) to the problem?
Use JUnit4 for Parameterized test feature. The following code should work.
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
#RunWith(value = Parameterized.class)
public class ParseTest {
private String parseValue;
public ParseTest(String parseValue) {
this.parseValue = parseValue;
}
#Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] { { "[1 2]" }, { "[1,2,]" } };
return Arrays.asList(data);
}
#Test(expected = ParseException.class)
public void testParseFailure1() throws Exception {
Parse.parse(parseValue);
}
}
For more info refer http://www.mkyong.com/unittest/junit-4-tutorial-6-parameterized-test/
Use the fail() method:
#Test
public void testParseFailure() throws Exception {
List<String> documents = Arrays.asList(
"[1 2]", // Missing comma
"[1, 2,]"); // Additional commas
for (String document : documents) {
try {
Parser.parse(document);
fail("Parsing " + document + " should have thrown a ParseException");
}
catch (ParseException e) {
// Expected, do nothing.
}
}
}
Here's an alternative, keeping the fail idea from the previous answer, for if you care about getting the right message in the exception.
public final class ParseFailureTest {
#Test
public void testParseFailure() throws Exception {
Map<String, String> documents = new LinkedHashMap<String,String>();
documents.put("[1 2]", "Missing comma");
documents.put("[1, 2,]", "Additional commas");
for (Entry<String,String> entry : documents.entrySet()) {
try {
Parser.parse(entry.getKey());
fail("Parsing " + entry.getKey() +
" should have thrown a ParseException");
} catch (ParseException e) {
assertEquals(entry.getValue(), e.getMessage());
}
}
}
}