I have the following code in a JUnit test (only including the relevant parts)
private String testRoot = System.getProperty("user.home");
private String destFail2 = testRoot + "/GoogleDrive/TestFail//..\\...//*";
#Test
public void given_NamedParameterizedFileSet_when_SavedWithInvalidFileName_then_Exception() {
String invalidFullPathToFileSet = fsPathDir + invalidBackupName;
//test save fully parameterized empty file set at non-existent directory
try {
FileSet fs = new FileSet(backupName, dest);
try {
FileSet.save(invalidFullPathToFileSet, fs);
fail("Save name is invalid, should refuse save");
} catch (IOException e) {
assert(true);
}
} catch (Exception e1) {
e1.printStackTrace();
fail("Could not create the file set");
}
}
The code for FileSet.save() is as follows:
public static void save(String fullPathToFile, FileSet fileSet) throws IOException {
ObjectOutputStream out = null;
Path outFilePath = Paths.get(fullPathToFile);
Path outDirPath = outFilePath.getParent();
if (Files.exists(outFilePath)) {
Files.delete(outFilePath);
}
if (!Files.exists(outDirPath)) {
Files.createDirectories(outDirPath);
}
try {
out = new ObjectOutputStream(new
BufferedOutputStream(Files.newOutputStream(outFilePath)));
out.writeObject(fileSet);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
}
The FileSet.save() method above SHOULD fail because it's being given what I think is an invalid file name, but somehow the code runs just fine without throwing an exception (on a Mac; haven't tried it on Windows).
Why is the code running?
Given the code, where do I look for the file it created?
What kind of filename do I need that is "bad?" I tried creating one with a colon (:) in it as it's supposed to be the only illegal character on a Mac, but even that works and it ends up creating a file with a colon in the middle of the name...
Is there a "better" way to write FileSet.save() (rather than using Path, should I be using File and passing the path in to the constructor as a string)?
Firstly, don't use assert keyword - if you run the java application without -ea parameter ("enable assertions"), this line will not execute at all. By the way assert true does nothing.
Secondly, exceptions that you do not care about, those that you are not testing, like e1 shouldn't be caught, declare that test method throws it. It will reduce the unnecessary complexity.
Finally, I would recommend using ExpectedException to do this assertion:
#Rule
public final ExpectedException expectedException = ExpectedException.none();
#Test
public void given_NamedParameterizedFileSet_when_SavedWithInvalidFileName_then_Exception() throws Exception {
String invalidFullPathToFileSet = fsPathDir + invalidBackupName;
FileSet fs = new FileSet(backupName, dest);
expectedException.expect(IOException.class);
FileSet.save(invalidFullPathToFileSet, fs);
}
This allows you to also check a message. It also checks that the exception is thrown after expect line. So if new FileSet(...) throws IOException, the test will fail. Note, ExpectedException needs to be annotated as #Rule to let junit now to perform a check at the end of test.
The test is successful because of improper exception handling. In the inner try-catch:
try {
FileSet.save(invalidFullPathToFileSet, fs);
fail("Save name is invalid, should refuse save");
} catch (IOException e) {
assert(true);
}
The line FileSet.save(invalidFullPathToFileSet, fs); throws an exception and for this reason the next line, which should fail the test, is not executed and the execution flow is redirected to the catch block where you simply assert(true) (which is a completely useless statement in a unit test) and then exit the inner and then the outer try-catch blocks, leading to successful execution.
What you should do is something like:
try {
FileSet.save(invalidFullPathToFileSet, fs);
} catch (IOException e) {
e.printStackTrace();
fail("Save name is invalid, should refuse save");
}
This will fail the test whenever an exception is thrown.
Related
I have try and catch block in JAVA code
import java.io.FileOutputStream;
import java.util.zip.ZipOutputStream;
public class TryTest {
public static void main(String[] args) {
String zipPath ="D:/test";
try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipPath))){
String Hello ="Hello";
System.out.println("==============>"+Hello);
}catch (Exception e) {
e.printStackTrace();
}
}
}
And my compiled class look like
/*
* Decompiled with CFR 0.145.
*/
....
try {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(string));){
String string2 = "Hello";
System.out.println("==============>" + string2);
}
....
I wounder why another try block added in compile time.
Full Source code in
https://github.com/vikram06/java_try_catch_bug
This is explained in the JLS 14.20.3.2 Extended try-with-resources :
The meaning of an extended try-with-resources statement:
try ResourceSpecification
Block
Catchesopt
Finallyopt
is given by the following translation to a basic try-with-resources
statement (§14.20.3.1) nested inside a try-catch or try-finally or
try-catch-finally statement:
try {
try ResourceSpecification
Block
}
Catchesopt
Finallyopt
The effect of the translation is to put the ResourceSpecification
"inside" the try statement. This allows a catch clause of an extended
try-with-resources statement to catch an exception due to the
automatic initialization or closing of any resource.
Furthermore, all resources will have been closed (or attempted to be
closed) by the time the finally block is executed, in keeping with the
intent of the finally keyword.
When you're using try with resources (I mean try (...) {... ) then Java compiler generates additional code section to display the stacktrace from local variable of type Throwable. That's because Java compiler is decomposing try with resources statement into separate tries - one for closing the resource and another for statements inside your try.
How is it displayed after decompilation - it depends on the decompiler you use.
Author of CFR here - short answer - CFR's 'resugaring' isn't perfect ;) (though the decompiled code is entirely correct, and valid.)
If you find something like this, feel free to submit a bug/improvement.
For what it's worth - the ACTUAL bytecode bears much less of a resemblance to the input - try using cfr with the arguments
--tryresources false --decodefinally false
And you get the unsugared code, which is much closer to the actual bytecode.
public static void main(String[] args) {
String zipPath = "D:/test";
try {
ZipOutputStream zipOut;
block11 : {
zipOut = new ZipOutputStream(new FileOutputStream(zipPath));
Throwable throwable = null;
try {
String Hello2332 = "Hello";
System.out.println("==============>" + Hello2332);
if (zipOut == null) return;
if (throwable == null) break block11;
}
catch (Throwable Hello2332) {
try {
throwable = Hello2332;
throw Hello2332;
}
catch (Throwable throwable2) {
if (zipOut == null) throw throwable2;
if (throwable == null) {
zipOut.close();
throw throwable2;
}
try {
zipOut.close();
throw throwable2;
}
catch (Throwable throwable3) {
throwable.addSuppressed(throwable3);
throw throwable2;
}
}
}
try {
zipOut.close();
return;
}
catch (Throwable Hello2332) {
throwable.addSuppressed(Hello2332);
return;
}
}
zipOut.close();
return;
}
catch (Exception e) {
e.printStackTrace();
}
}
Ive two method that throw the same exception throws IOException
the problem is that each method throw it from different reason, I wrap the methods
in the main with try catch, what is the recommended way to solve it ?
I need different message for each exception with the same type..
public static void main(String[] args) {
try{
….
readFile(path);
convert(file)
} catch (IOException e) {
…..
}
private static String readFile(String path) throws IOException {
//Here files requires IOException - Reason here cannot Read file
String lineSeparator = System.getProperty("line.separator");
List<String> lines = Files.readAllLines(Paths.get(path));
}
private static String convert(String file) throws IOException {
//Here reader requires also ioException- Reason here cannot parse file
ObjectMapper reader = new ObjectMapper(new YAMLFactory());
Object obj = reader.readValue(file, Object.class);
}
There are several ways you could approach this. One way, perhaps the heaviest in terms of new code you would need to write, would be throw a custom exception from each of your helper methods. Then you could catch each specific exception in a separate block.
But what I might recommend here is that you simply wrap each of the two calls to your helper methods in separate try-catch blocks:
try {
readFile(path);
} catch (IOException e) {
// handle first exception here
}
// more code
try {
convert(file)
} catch (IOException e) {
// handle second exception here
}
This is fairly clean and doesn't require a lot of refactoring. If you keep encountering this problem, then maybe consider creating custom exceptions for your application. If you have a look at many Java libraries, you will see that they often use their own custom exceptions.
If you wanted to go the route of using a custom exception, you could define one, e.g.
public class FileReadIOException extends Exception {
public FileReadIOException(String message) {
super(message);
}
}
and then use it:
private static String readFile(String path) throws FileReadIOException {
try {
String lineSeparator = System.getProperty("line.separator");
List<String> lines = Files.readAllLines(Paths.get(path));
}
catch (Exception e) {
throw new FileReadIOException(e.getMessage());
}
}
try {
readFile(path);
// more code
convert(file)
} catch (FileReadIOException e) {
// handle first exception here
} catch (SomeOtherException e) {
// handle second exception here
}
The above code showing custom exception is a bit contrived, because the reality is that all of your code is throwing IOException. Creating custom exceptions in your case does not add much value, because they are already (rightfully) throwing an IOException. I'm not sure that it doesn't make sense to handle just one type of exception. More typically, if you were working on a large enterprise application, you would use custom exceptions to handle situations which go wrong in your own custom code.
My way is usually to create your own exception and throw it like that
public class Snippet {
public static void main(String[] args) {
try {
String path = "";
readFile(path);
String file = "";
convert(file);
} catch (MyException e) {
// do whatever
}
}
private static String readFile(String path) throws MyException {
try {
String lineSeparator = System.getProperty("line.separator");
List<String> lines = Files.readAllLines(Paths.get(path));
} catch (Exception e) {
throw new MyException("Custom 'readFile' message", e);
}
}
private static String convert(String file) throws MyException {
try {
ObjectMapper reader = new ObjectMapper(new YAMLFactory());
Object obj = reader.readValue(file, Object.class);
} catch (Exception e) {
throw new MyException("Custom 'convert' message", e);
}
}
}
class MyException extends Exception {
private static final long serialVersionUID = -3166824380774329449L;
public MyException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
}
Tim's way is valid too.
#OP The best person to solve this would be you yourself.
There are quite easily multiple ways to solve that. Check which one suits you more properly.
One of the solution as per me is below. This is based on the reason IOException is superclass to many other exceptions. IOException documentation
try {
readFile(path);
} catch ( FileNotFoundException e) {
// handle first exception here
} catch ( EOFException e) {
// handle 2nd exception here
}
For the above to work you would need to know which type of IOException is being thrown.
Another solution is check individual exception messages when you know what are expected messages you may receive.
try {
readFile(path);
} catch ( IOException e) {
if(e. getMessage().contains("TXT 1...") {
//Case handle #1
} else if(e. getMessage().contains("TXT 2...") {
//Case handle #2
}
}
The best way to handle exception is not to have them. When exception is thrown, it indicates that natural lifecycle of your application has been interrupted for one reason or another. Most exceptions are self-explanatory and provide you with precise explanation of what happend, therefore creating new exceptions and re-mapping those thrown is almost always counterproductive and may result in more confusion than usefulness(especial if you work in a team).
Furthermore exceptions doesn't need to be terminal, in most cases, a scenario can be devised to retry/prompt different input etc. to ensure that lifecycle is not interrupted. Killing an application on exception can create more problems in some cases (e.g: not closing files properly, hence losing processed data).
Now to your actual problem. If you have two or more components, that throws unrelated exceptions(name is not a relation in this case), it is best not to have them in the same try/catch structure as less workaround will be necesary to scrap that one part, instead of the whole thing which can still exit on its own, or doesn't even need to be initiated.
Here is my 5 cents
public static void main(String[] args) throws Exception {
String path = "path";
String path2 = "path2";
try{
readFile(path);
} catch (IOException e) {
throw new Exception("read file exception", e);
}
try{
convert(path2);
} catch (IOException e) {
throw new Exception("convert exception", e);
}
}
private static String readFile(String path) throws IOException {
//Here files requires IOException - Reason here cannot Read file
String lineSeparator = System.getProperty("line.separator");
List<String> lines = Files.readAllLines(Paths.get(path));
}
private static String convert(String file) throws IOException {
//Here reader requires also ioException- Reason here cannot parse file
ObjectMapper reader = new ObjectMapper(new YAMLFactory());
Object obj = reader.readValue(file, Object.class);
}
I have catch block, i want to execute the catch block. My Class file is,
public class TranscoderBean implements TranscoderLocal {
public byte[] encode(final Collection<?> entitySet) throws TranscoderException {
Validate.notNull(entitySet, "The entitySet can not be null.");
LOGGER.info("Encoding entities.");
LOGGER.debug("entities '{}'.", entitySet);
// Encode the Collection
MappedEncoderStream encoderStream = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
// Create the encoder and write the the DSE Logbook messgae
encoderStream = new MappedEncoderStream(outputStream, this.encoderVersion);
encoderStream.writeObjects(new ArrayList<Object>(entitySet), false);
encoderStream.flush();
}
catch (Exception e) {
LOGGER.error("Exception while encoding entities", e);
throw new TranscoderException("Failed to encode entities", e);
}
finally {
if (encoderStream != null) {
try {
encoderStream.close();
}
catch (IOException e) {
LOGGER.error("Exception while closing the endcoder stream.", e);
throw new TranscoderException("Failed to close encoder stream", e);
}
}
}
}
My Test Class file is,
public class TranscoderBeanTest {
private TranscoderBean fixture;
#Mock
MappedEncoderStream mappedEncoderStream;
#Test
public void encodeTest() throws TranscoderException {
List<Object> entitySet = new ArrayList<Object>();
FlightLog log1 = new FlightLog();
log1.setId("F5678");
log1.setAssetId("22");
FlightLog log2 = new FlightLog();
log2.setId("F5679");
log2.setAssetId("23");
entitySet.add(log1);
entitySet.add(log2);
MockitoAnnotations.initMocks(this);
try {
Mockito.doThrow(new IOException()).when(this.mappedEncoderStream).close();
Mockito.doReturn(new IOException()).when(this.mappedEncoderStream).close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encode = this.fixture.encode(entitySet);
Assert.assertNotNull(encode);
}
}
I have tried, Mockito.doThrow and Mockito.doReturn methods but still the catch block is not executed. What am doing wrong.
To test a try-catch block, you can use a TestNG way which consists in implementing a test method with the following annotation expectedExceptions.
The code of this method, you have to implement it in order to provoke this exception, so the catch block will be executed.
You can have a look at http://testng.org/doc/documentation-main.html#annotations
Are you sure you have the right test class. I do not see any reference to TranscoderBean in your
You expect Mockito to do things that it does not claim to do:
Mockito.doThrow(new IOException()).when(this.mappedEncoderStream).close();
This statement asserts that whenever someone calls close() on the mapperEncoderStream-Object will receive an IOException. You never call close.
Try to add mapperEncoderStream.close(); after your Mockito-actions and the catch block will be entered - but note: this won't help you with your problem, since mockito cannot help here.
For your problem you can consider following alternative:
rewrite
encoderStream = new MappedEncoderStream(outputStream, this.encoderVersion);
to
encoderStream = createMappedEncoderStream(outputStream);
MappedEncoderStream createMappedEncoderStream(ByteArrayOutputStream outputStream) {
return new MappedEncoderStream(outputStream, this.encoderVersion);
}
this lets you inject the mock as dependency.
Then init your fixure like this:
fixture = new TranscoderBean() {
MappedEncoderStream createMappedEncoderStream(ByteArrayOutputStream outputStream) {
return mappedEncoderStream; //this is your mock
}
}
This injects the mock into your TranscoderBean.encode method.
Then change your mock Annotation:
#Mock(answer=CALLS_REAL_METHODS)
MappedEncoderStream mappedEncoderStream;
This is needed, because your encode method does not only call close on mappedEncoderStream, but also writeObjects and flush. These calls may throw exceptions so they have to be mocked or replaced by calls to the real object.
prune your test like that
#Test(expected=TranscoderException.class)
public void encodeTest() throws TranscoderException {
//... same as above
MockitoAnnotations.initMocks(this);
Mockito.doThrow(new IOException()).when(this.mappedEncoderStream).close();
this.fixture.encode(entitySet); //this will throw an exception
}
This does the following:
the encode method does not return null! It throws a TranscoderException, so it is placed as expected
override the close method with exception throwing
call encode
So I have a method to write a string to a file:
public static void saveStringToFile(String path, String string) {
File file = new File(path);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileWriter out = null;
try {
out = new FileWriter(path);
out.write(string);
if (out != null) {
out.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
And my test class with the following setUp method which runs before each test (to delete the testfile before each one):
public static final String TEST_FILE = "somefile.xml";
//...
#Before
public void setUp() throws IOException {
if (MyCustomClass.fileExists(TEST_FILE)) {
new File(TEST_FILE).delete();
}
}
Each of my test tries to write something to the file using the method saveStringToFile(). It succeeds like for a couple of times, but a some random point I finally get the java.io.IOException: Access is denied. Got no idea why this happens - sometimes it occurs in test1, sometimes in test3...
It was working OK, when I was using Java7 FileIO, but I needed to migrate back to Java6...
Are you testing that you are able to create, write to and delete a file, or are you testing what is written to the file?
If the latter, then perhaps you should be mocking/overriding the saveStringToFile( ... ) method and instead focus on verifying that the code you're unit testing actually produces the correct output.
If the former, then I quite agree with #Omaha's suggestion that your test runner is likely running several tests in parallel.
Hope that helps.
There's some problems with the exception handling. The call to out.close() should be within a separate try-catch block inside a finally block. If an exception is thrown when writing to the file, the file is never closed.
I would recommend looking at something like Apache Commons IO which has many useful IO methods like FileUtils.writeStringToFile().
So, probably JUnit wasn't running it parrallel, cause as I suppose It doesn't do it by default.
The problem was in my readfile method:
private String readFile(String path) throws FileNotFoundException {
return (new Scanner(new File(path))).useDelimiter("\\Z").next();
}
To work fine I had to fix
private String readFile(String path) throws FileNotFoundException {
Scanner scanner = (new Scanner(new File(path)));
String s = scanner.useDelimiter("\\Z").next();
scanner.close();
return s;
}
The close() method for Scanner was the key...
I have a simple servlet where I write to a file if it has a queryparameter 'hello', and since this is a test I want to display the error the the webpage also.
IntelliJ is complaining that I am not catching the IOException, not sure what's wrong:
private static void WriteToFile(String filePath, String fileName, String fileData) {
FileWriter writer = null;
try {
writer = new FileWriter(fileName);
writer.write(fileData);
} catch(IOException ex) {
} finally {
if(writer != null) {
writer.close();
}
}
}
Also, in my exception, I noticed on the web most people write:
How can I output the error to the web page?
You're not catching IOException when you call writer.close(); in the finally block.
You're also completely swallowing any IOException thrown in the main code, which is a really bad idea. If something's goes wrong, you'll have no idea what's happening.
I would personally suggest that you let that method throw the exception to the caller:
private static void writeToFile(String filePath, String fileName,
String fileData) throws IOException {
FileWriter writer = new FileWriter(fileName);
try {
writer.write(fileData);
} finally {
writer.close();
}
}
Note that if the try block throws an exception and the finally block does, you'll effectively "lose" the original exception. You may want to suppress exceptions throw when closing.
Or just use Guava which makes all of this simpler anyway with its Files class.
Or if you're using Java 7, you could use a try-with-resources statement.
(I note that you're ignoring filePath by the way - why?)
You can write in catch block too : writer.write(errorMessage);
or you may redirect to Error page if error occured