Reputation: 2423
I'm writing a test for a piece of code that has an IOException catch in it that I'm trying to cover. The try/catch looks something like this:
try {
oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
} catch (IOException e) {
LOGGER.error("Bad news!", e);
} finally {
The easiest way seems to make FileOutputStream throw a FileNotFoundException, but perhaps I'm going about this all the wrong way.
Anyone out there have any tips?
Upvotes: 1
Views: 2769
Reputation: 697
I hope this is what you meant.
if(new File(cachedFile).exists()) {
oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
//do your code here
} else {
throw new FileNotFoundException("File doesn't exist!");
}
Upvotes: 0
Reputation: 14678
There are two parts to any test: getting it to happen and measuring that you got the correct result.
The easiest answer is the one that's already been mentioned, which is to set cacheFileName
to a file that will never exist. This is likely the most practical answer in this situation.
However, to cause an arbitrary condition such as an IOException
, what you really want is Fault Injection. This forces faults in your code without forcing you to instrument your source code. Here are a few methods for doing this:
ObjectOutputStream
or FileOutputStream
. In test code the implementation would throw an IOException
when you wanted to, and in production code would not modify the normal behavior.There are other answers to fault injection on Java; for instance a product called AProbe pioneered what could be called AOP in C long ago, and they also have a Java product.
Getting the exception thrown is a good start, but you also have to validate that you got the right result. Assuming that the code sample you have there is correct, you want to validate that you logged that exception. Someone above mentioned using a Mock object for your logger, which is a viable option. You can also use AOP here to catch the call to the logger.
I assume that the logger is log4j; to solve a similar problem, I implemented my own log4j appender which captures log4j output: I specifically capture only ERROR
and FATAL
, which are likely to be the interesting log messages in such a case. The appender is referenced in log4j.xml
and is activated during the test run to capture error log output. This is essentially a mock object, but I didn't have to restructure all my code that got a log4j Logger
.
Upvotes: 2
Reputation: 140061
cacheFileName = "thisFileShouldNeverExistAndIfItDoesYouAreScrewingUpMyTests";
Sure you could take steps and jump thru hoops to programatically make sure that the file name will never, ever, ever exist, or you could use a String that will never exist in 99.99999% of cases.
Upvotes: 0
Reputation: 61536
From your comment:
Yes, I suppose the question should really have been "How do I create a file that does not exist on both Linux and Windows?" On windows, I can use 'new File("X:/")', where X: is a drive letter that does not exist. On Linux, this does not work because that is a valid file name.
Look at java.io.File.createTempFile. Use it to create the file and then delete it.
Probably pass it something like:
File tempFile;
tempFile = createTempFile(getClass().getName(),
Long.toString(System.currentTimeMillis());
tempFile.delete();
That should give you a unique name in a platform indendent manner that you can safely use without (much) fear of it existing.
Upvotes: 4
Reputation: 2879
As the code is currently written, you could try to mock out the error() call on the LOGGER object and check to see if it gets called when you expect an IOException.
Your desire to test may have uncovered a fundamental problem with the code as it's written. An error is occurring but there's no boolean or flag value (set the filename to a special pattern) that provides other sections of code to determine if writing to the file was successful. If this is contained in a function, maybe you could return a boolean or set an object level variable.
Upvotes: 0
Reputation:
Two easy ways would be either set cacheFileName to a non-existent file or set the specified file to read-only access.
-John
Upvotes: 0
Reputation: 29139
A FileNotFoundException would obviously trigger the catch. The javadoc states the cases where it will be thrown.
You should also consider that the ObjectOutputStream constructor can throw an IOException so may want to cover this case in your tests.
Upvotes: 0
Reputation: 45754
I'm writing a test for a piece of code that has an IOException catch in it that I'm trying to cover.
I'm not entirely sure I understand your goal, but if you want to test if the exception is thrown, you can tell the test you expect it to throw the exception:
@Test(expected=IOException.class)
Your test will then fail if the exception is not thrown, and succeed if it is thrown (like, if the cacheFileName
file does not exist).
Upvotes: 0
Reputation: 5117
You could set cacheFileName
to an invalid name or to one you know doesn't exist.
Upvotes: 5