Function to be tested:
public void deleteFile(File file) {
try {
Files.delete(file.toPath()) ;
log.info("Csv file deleted from system succesfully after processing the data");
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
Test code:
#Test
void testExceptionDuringDeletingFile() {
helper=mock(Helper.class);
//String bucket ="bucket";
//String key = "key";
File file = new File("");
doThrow(IOException.class).when(helper).deleteFile(file);
Assertions.assertThrows(IOException.class,()->helper.deleteFile(file));
}
But I am getting the following exception:
org.mockito.exceptions.base.MockitoException: Checked exception is
invalid for this method! Invalid: java.io.IOException at
com.lululemon.product.ap.reprocess.producer.HelperTests.testExceptionDuringDeletingFile(HelperTests.java:191)
at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method) at
Because your deleteFile() method doesn't throw the IOException. You catch it in your method implementation and do something with it.
And, your mocked Helper class instance really can't throw IOException from the deleteFile() method because the real deleteFile() method doesn't.
Throw the IOException from your method and you won't get the error.
deleteFile method:
public void deleteFile(File file) throws IOException {
try {
Files.delete(file.toPath());
log.info("Csv file deleted from system successfully after processing the data");
} catch (IOException e) {
throw new IOException("Couldn't delete file. Try again!");
}
}
Test method:
#Test
void testExceptionDuringDeletingFile() throws IOException {
File file = new File("");
Helper helper = mock(Helper.class);
doThrow(IOException.class).when(helper).deleteFile(file);
Assertions.assertThrows(IOException.class, () -> helper.deleteFile(file));
}
Related
I runt into something strange. I have a method to read from a CSV file, line by line. The method takes the filePath and in my JUnit test, I'm testing this method with the wrong filePath expecting to get a FileNotFoundException. The thing is that JUnit5 doesn't throw that exception but in the eclipse console I can see that the JVM throws that exception, so I'm struggling to understand why
I've set up my test code to throw the exception but it doesn't get thrown. I tried to catch Exception but still no joy.
Here is the method and the test method
public void readData(String COMMA_DELIMITER, String READ_FILE_PATH) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(READ_FILE_PATH));
String line = "";
//Read to skip the header
br.readLine();
//Reading from the second line
while ((line = br.readLine()) != null)
{
String[] employeeDetails = line.split(COMMA_DELIMITER);
populateModel(employeeDetails);
}
//Lets print the Employee List
for(Employee e : empList)
{
System.out.println(e.getName() + "; " + e.getSurname() + "; " + e.getDateOfBirth() + "; " + e.getSex());
}
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
#Test
void testWrongFilePath() {
String READ_FILE_PATH_WRONG = System.getProperty("user.dir") + "/teest/XXXFile.csv";
System.out.println(READ_FILE_PATH_WRONG);
Assertions.assertThrows(FileNotFoundException.class, () -> {
readData.readData(COMMA_DELIMITER, READ_FILE_PATH_WRONG);
});
}
In the console, I get the FIleNotFOundException, but the output of the test says that
org.opentest4j.AssertionFailedError: Expected java.io.FileNotFoundException to be thrown, but nothing was thrown.
You cannot expect from your Assertion framework to catch an exception that is caught inside your SUT:
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
You either have to :
Log then rethrow same / different exception and assert on that.
Make your method return Boolean as a success equivalent which you can then assert on.
You're catching the FileNotFoundException within readData.
Try refactoring so that you don't have a try-catch, and have public void readData(String COMMA_DELIMITER, String READ_FILE_PATH) throws IOException { ...
(FileNotFoundException is a subclass of IOException.)
assertThrows(Class<T> expectedType, Executable executable)
doesn't assert that an exception is thrown at a time in your code (which is the true in your case). But that asserts that the statement invoked in the Executable lambda throws an exception (which is false in your case).
Since you caught the FileNotFoundException in the method under test, the exception is never propagates to the lambda return and JUnit can only emit an error because the expected exception was not encountered.
To assert such a thing, don't catch the exception by removing the catch statement and instead of declare throws FileNotFoundException in the declaration of the tested method :
public void readData(String COMMA_DELIMITER, String READ_FILE_PATH) throw FileNotFoundException {...}
Your method doesn't throw FileNotFoundException: you catch it, print the stack trace, and carry on as if no exception occurred:
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JUnit isn't magic: it can't detect things that happen inside the method, other than by detecting side effects (values returned, uncaught exceptions, mutating state).
I'm trying to use Suppliers#memorize on a function that throws IOException
Snippet:
private Supplier<Map> m_config = Suppliers.memoize(this:toConfiguration);
This gives an exception:
Unhandled exception type IOException
so I had to do something like this:
public ClassConstructor() throws IOException
{
m_config = Suppliers.memoize(() -> {
try
{
return toConfiguration(getInputFileName()));
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
});
if(m_Configuration == null) {
throw new IOException("Failed to handle configuration");
}
}
I would like the CTOR to forward the IOException to the caller.
The proposed solution is not so clean, is there a better way to handle this situation?
Use UncheckedIOException
You're tagging java-8, so you should use the UncheckedIOException which is present for this very use case.
/**
* #throws java.io.UncheckedIOException if an IOException occurred.
*/
Configuration toConfiguration(String fileName) {
try {
// read configuration
} catch (IOException e) {
throw new java.io.UncheckedIOException(e);
}
}
Then, you can write:
m_config = Suppliers.memoize(() -> toConfiguration(getInputFileName()));
I'm a Pythonista moving into Java/Scala, and I am wondering how to handle the case where you want an exception to be thrown if it occurs. Take the following toy example:
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In Python I would want this to throw an error if the file isn't found, and let the calling code handle the exception. Is it convention just to re-throw the same exception?
You can make your method throw those exceptions :
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
//handle the exception you want to handle
e.printStackTrace();
}
}
}
Just make sure you declare your method with the throws statement, or your compiler might not like it ;)
You can also go this way (let's call this a semi-exception-handling) :
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException, IOException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
/*Some code to clear some data or to handle the
exception but still throw an exception higher*/
throw e;
}
}
}
You can just do the following...
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
}
}
}
In any part of your code you can throw a throwable object, such as an Exception.
You should also state it in the method signature, letting the JVM know you'll handle that Exception in a caller's block.
Example:
public void save(List<Person> people) throws FileNotFoundException{
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
}
}
You need to consider if the calling code actually knows what to do with the specific exception. You have defined an API about saving a collection of Person. The calling code knows only about a Person and has no idea ideally where the save is done.
If you throw a lower level exception about the file not found you are leaking the abstraction and you won't be able to change the implementation easily if the calling code is starting to be aware of where things are saved.
The proper approach would be to throw an "business" exception like PersonNotPersisted or PersonNotSaved since this is something the calling code would understand and avoid the low level IO exceptions to the higher layer
If you declare a method to throws an checkedexception you dont need to catch it or any of it subtypes:
public void save(List<Person> people) throws IOExcetion {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
}
}
If you want to handle the exception before you can also do like:
public void save(List<Person> people) throws IOException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
The keyword 'throw' fires the exception to the caller.
PropertiesConfiguration.java doesn't have a close() method. Is there something else that needs to be done to release the file? I want to be sure before I use this in production. I've looked through the code and I don't see anything. I'm not entirely sure how PropertiesConfiguration.setProperty() is working without opening a connection to the file that would then have to be closed.
In org.apache.commons.configuration.PropertiesConfiguration the input (stream, path, url, etc...) is of course closed when the properties were loaded in the PropertiesConfiguration instance.
You could have the confirmation in the void load(URL url) method of org.apache.commons.configuration.AbstractFileConfiguration.
Here is how this method is called :
1) PropertiesConfiguration constructor is invoked :
public PropertiesConfiguration(File file) throws ConfigurationException
2) which calls its super constructor :
public AbstractFileConfiguration(File file) throws ConfigurationException
{
this();
// set the file and update the url, the base path and the file name
setFile(file);
// load the file
if (file.exists())
{
load(); // method which interest you
}
}
3) which calls load() :
public void load() throws ConfigurationException
{
if (sourceURL != null)
{
load(sourceURL);
}
else
{
load(getFileName());
}
}
4) which calls load(String fileName):
public void load(String fileName) throws ConfigurationException
{
try
{
URL url = ConfigurationUtils.locate(this.fileSystem, basePath, fileName);
if (url == null)
{
throw new ConfigurationException("Cannot locate configuration source " + fileName);
}
load(url);
}
catch (ConfigurationException e)
{
throw e;
}
catch (Exception e)
{
throw new ConfigurationException("Unable to load the configuration file " + fileName, e);
}
}
5) which calls load(URL url)
public void load(URL url) throws ConfigurationException
{
if (sourceURL == null)
{
if (StringUtils.isEmpty(getBasePath()))
{
// ensure that we have a valid base path
setBasePath(url.toString());
}
sourceURL = url;
}
InputStream in = null;
try
{
in = fileSystem.getInputStream(url);
load(in);
}
catch (ConfigurationException e)
{
throw e;
}
catch (Exception e)
{
throw new ConfigurationException("Unable to load the configuration from the URL " + url, e);
}
finally
{
// close the input stream
try
{
if (in != null)
{
in.close();
}
}
catch (IOException e)
{
getLogger().warn("Could not close input stream", e);
}
}
}
And in the finally statement, you can see that the inputstream is closed in any case.
We are having some issue with XML file generation using JAXB.(The generated file is corrupted/jumbled even if we validate against XSD). But no errors are reported in server logs(catalina.out)
While we were doing the investigations, we happened to found the following code segment in com.sun.xml.internal.bind.v2.runtime.MarshallerImpl(This is the runtime class used by java to marshall the JAXB objects to XML).
/**
* All the marshal method invocation eventually comes down to this call.
*/
private void write(Object obj, XmlOutput out, Runnable postInitAction) throws JAXBException {
try {
if( obj == null )
throw new IllegalArgumentException(Messages.NOT_MARSHALLABLE.format());
if( schema!=null ) {
// send the output to the validator as well
ValidatorHandler validator = schema.newValidatorHandler();
validator.setErrorHandler(new FatalAdapter(serializer));
// work around a bug in JAXP validator in Tiger
XMLFilterImpl f = new XMLFilterImpl() {
#Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
super.startPrefixMapping(prefix.intern(), uri.intern());
}
};
f.setContentHandler(validator);
out = new ForkXmlOutput( new SAXOutput(f) {
#Override
public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws SAXException, IOException, XMLStreamException {
super.startDocument(serializer, false, nsUriIndex2prefixIndex, nsContext);
}
#Override
public void endDocument(boolean fragment) throws SAXException, IOException, XMLStreamException {
super.endDocument(false);
}
}, out );
}
try {
prewrite(out,isFragment(),postInitAction);
serializer.childAsRoot(obj);
postwrite();
} catch( SAXException e ) {
throw new MarshalException(e);
} catch (IOException e) {
throw new MarshalException(e);
} catch (XMLStreamException e) {
throw new MarshalException(e);
} finally {
serializer.close();
}
} finally {
cleanUp();
}
}
private void cleanUp() {
if(toBeFlushed!=null)
try {
toBeFlushed.flush();
} catch (IOException e) {
// ignore
}
if(toBeClosed!=null)
try {
toBeClosed.close();
} catch (IOException e) {
// ignore
}
toBeFlushed = null;
toBeClosed = null;
}
The method write(Object obj, XmlOutput out, Runnable postInitAction) calls the cleanup method in the finally clause and there is the flushing is happening. But in this cleanup method while flushing if any IOException happens, they ignore the exception.
We are wondering, whether this segments generated the corrupted XML as it does not throw back the exception and simply eats up the exception.
Also we have found the following statement in API documentation of XML serializer.
class: org.apache.xml.serialize.XMLSerializer
If an I/O exception occurs while serializing, the serializer will not throw an exception directly, but only throw it at the end of serializing (either DOM or SAX's DocumentHandler.endDocument().
Any help is appreciated.
Regards,
Mayuran
The IOException is not being ignore its being wrapped in a MarshalException and re thrown. The underlying issue should be present in the MarshalException you are receiving.