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?
You could set cacheFileName to an invalid name or to one you know doesn't exist.
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.
There are two parts to any test: getting it to happen and measuring that you got the correct result.
Fault Injection
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:
Mock objects You could use a factory method to create an overridden 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.
Dependency Injection In order to get your Mock Object in the right place you could use a framework such as Spring or Seam to "inject" the appropriate object into the class that's doing the work. You can see that these frameworks even have a priority for objects that will be injected, so that during unit testing you can override the production objects with test objects.
Aspect Oriented Programming Instead of changing the structure of your code at all, you can use AOP to inject the fault in the right place. For instance, using AspectJ you could define a Pointcut where you wanted the exception to be thrown from, and have the Advice throw the desired exception.
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.
Validation
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.
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).
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.
Two easy ways would be either set cacheFileName to a non-existent file or set the specified file to read-only access.
-John
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.
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.
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!");
}
Related
I am new to Java, I read that checked exception get raised during compile time only i.e. program will not compile successfully if there is a checked exception which is not handled or thrown.
If something is preventing a compiler to compile a code, then we could just erase it or recode it in another way so that problem doesn't exist.
For example, if we are trying to open a file which is not there in system, we should not just open it. So why the need to handle/throw these exceptions ?
Your conceptual problem here is that you are conflating what happens at compile time and what happens at runtime; i.e. when the program is compiled by the programmer and when it is run by the user.
At compile time the compiler analyses the program to determine what exceptions could be thrown. For example
public static void main(String[] args) {
FileInputStream fis = new FileInputStream(args[0]); // HERE
}
The FileInputStream(String) constructor is declared as throws IOException. (Look it up.) So the compiler knows that the statement at HERE could throw an IOException. And IOException is a checked exception. (Look it up.)
It doesn't know that it will. It cannot possibly know that it will ... because it doesn't know what args[0] will contain. That is only known at runtime; i.e. when the program is run and the user supplies some command line arguments.
Q: What does checked exception mean here?
Well it means the main method either has to be declared as (for example) throws IOException, or it must catch it in a try-catch statement.
Q: So why is is a checked exception?
Because it was declared that way!
Q: Why was it declared that way?
To force the programmer to do deal with the possibility that the file being opened does not exist, is not readable, and so on. When the program is (eventually) run.
The compiler is saying "do something about this thing that might happen ...".
Just to reiterate. The compiler cannot check that the file exists because it doesn't know what pathname the user is going to provide. And even if it did know, AND it checked1 that the file existed at compile, it couldn't know if the file was going to still exist at runtime, possibly on a completely different machine on a different network ... many years in the future.
1 - This is hypothetical. It doesn't check. It would be pointless.
You shouldn't see exception handling as a problem but as a feature.
Assume exceptions wouldn't exist.
var file = new File("test.txt");
if (!file.exists()) {
file.createNewFile();
}
var writer = new FileWriter(file);
// ...
What could go wrong?
Between the check whether the file exists and opening the reader, the file might have been removed by another thread/process. So even though you created it, it's gone -> you need to somehow lock the file
Your memory is full, hence the file could not be created -> you need to check the result of createNewFile for that.
The file exists, but is a directory.
The file is locked, because another process is writing to it -> You need to check if it is being written to.
This would do it (still assuming no exceptions):
var file = new File("test.txt");
if (!file.exists()) {
if(file.createNewFile()) {
if (!file.isDirectory()) {
if (!isUsed(file)) {
var writer = new FileWriter(file);
// ...
}
}
}
}
This is a lot of code and still doesn't handle the first problem.
Whereas
var file = new File("test.txt");
try {
var writer = new Filewriter(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
is way shorter, clearer, easier to understand.
Also, usually, it is more likely that everything works as supposed that that any of these problems occur. So instead of assuming all the worst and doing multiple checks beforehand, one just assumes the best and if something fails, you look for the reason.
This also impacts the runtime. If you run the no-exception code 1000 times, all these checks will be run a 1000 times, no matter if they fail or not. For the exception-code this is not the case, the might never be run at all.
Checked exception in Java have to be handled, that is why the compiler will complain about and didn't compile the code.
But the exception itselfs will not be raised until runtime, in case it happens.
When you write your code you should just handle properly all your checked exception, so you have to write a try catch block or just return the exception from the method.
If you use some library that raises checked exception you can just handle in one of the 2 ways I have already explained.
But in your code you can choose to use unchecked exceptions.
Those kind of exceptions can be ignored and the compiler will be just fine.
Of course your app will crash if one of those unchecked exception is raised while execution and it is not caught.
But that can be desirable in certain situation, where there is no right way to handle the Exception and it is generally a subclass of Error.
Anyway you should not think about on how to handle the error cases in your code but only Exceptions.
More: Exception class, Error class
This is a very well discussed topic. Out of many links, I did find the below two useful.
1,
2
My questions is this:
I am writing multiple methods, some for general purposes- say, writing into file, reading from file, splitting a string using some regex.
I am calling these methods from different parts of my application- say class1, class 2 and class 3 calls the file writing method, but with different file names and data.
Where should I include try catch and throws?
1. The outermost method, say the main, from where I am calling the class1, class2 and class 3 methdods have one set of try, catch and use throws in the innermost functions.
Or, have a try catch in the innermost-None to the outer files..
Which is a better option and why? Are there any other ways of dealing with this.
Thanks
The heart of this matter is how to decide logically where your exceptions need to be handled.
Let's take an example. A method that takes a File object and performs some operation.
public void performFileOperation(File f) throws FileNotFoundException{
// Perform logic.
}
In this case, chances are that you want the class/method calling this method to handle the Exception. If you had a try/catch block in the performFileOperation() method, then the method calling the performFileOperation() method would never know if the operation failed (and therefore can't know what to do about it).
It is really a matter of where it makes sense to handle the Exception that is thrown. You need to work out which sections of your code need to know that an exception has occurred, and use try/catch blocks there. If the next level up needs to know as well, then the catch block can throw the Exception so the method further up the stack can know about and handle it as well.
Another good way to look at it is that most exceptions need to be handled. Something needs to be done about them. If your method is not in a position to do something significant to handle that exception then it needs to throw the Exception until it makes it's way to somewhere that can meaningfully handle (read, do something about) it.
I hope this helps.
Too often one sees the following pattern in enterprising Java programs
public Something myMethod() throws MyException {
try {
// may throw checked DbException:
Connection c = openDataBase("connectionstring");
// ... other code throwing more checked exceptions ...
} catch(DbException e) {
throw new MyException(e);
}
return something;
}
...or any other mechanism to "cast" one checked exception type that is not declared in the method header to the one that is. Very often this "try-catch-cast"-block must go into every method of such a class.
I wonder, how to implement an annotation, that catches and converts exceptions?
The using code should then look like this:
#ConvertException(MyException, DbException)
public Something myMethod() throws MyException {
// may throw checked DbException:
Connection c = openDataBase("connectionstring");
// ...
return something;
}
Of course, Maybe one has to write MyException.class or "MyException" instead. It should also be possible to chain these annotations, or list multiple exceptions to convert.
My guess is that the annotation would introduce a wrapper function with the catching code block that would call the original function. The annotation would then only have compile-time-retension (and not run-time-retension).
I don't advocate that its wise to do this, it probably isn't because these annotations change the program semantics. It may well be an academical question to "just learn"...
Annotations don't do anything at all by themselves. You need a tool that evaluates them and does some code changing according to them.
In your case, AspectJ seems to be the best match.
My advice would be to read AspectJ in Action (2nd ed) by Ramnivas Laddad.
As you can see from it's Table of Content, it contains a chapter about exception softening, which is almost exactly what you want.
And since you tagged this question dependency-injection, assuming you use Spring, here is Spring's own Exception translation mechanism
Yes, this should be possible by creating an annotation processor that uses the compiler tree api (javac.tree package) to manipulate the source code while it's being compiled.
The problem is of course that this annotation processor now must be present whenever the code is compiled, and many tools that process source code (most prominently IDEs) may not know about it and consider the code invalid.
I have some functionality that I want to mock out being called from main (static: I've read about that too - jmock mocking a static method). i recently read that JMock doesn't support the mocking of static functions. Well, the associated code (that's giving me a problem) must be called from main, and must be in the class with main...
Sample source
Test code
Right now, I want to ensure that my main has a test to make sure that the file exists before it proceeds. Problem is, I have my program getting user input from the console, so I don't know how to mock that out? Do I just go down to that level of granularity, specifying at every point along the way what happens, so that I can write about only one operation in a function that returns the user's input? I know that to write the tests well, when the tests are run, they should not ask for the user input, I should be specifying it in my tests somehow.
I think it has to do with the following:
How to use JMock to test mocked methods inside a mocked method
I'm not that good with JMock...
If the readInput() method does something, like, say:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
return in.readLine();
Then you might be able to get away with a test that goes something like:
InputStream oldSystemIn = System.in;
InputStream mockSystemIn = context.mock(InputStream.class);
System.setIn(mockSystemIn);
context.checking(new Expectations() {{
// mock expected method calls and return values
}});
// execute
// verify
System.setIn(oldSystemIn);
You can use System Rules instead of mocking System.out and System.in.
public void MyTest {
#Rule
public TextFromStandardInputStream systemInMock = emptyStandardInputStream();
#Test
public void readTextFromStandardInputStream() {
systemInMock.provideText("your file name");
//your code that reads "your file name" from System.in
}
}
Stefan Birkner's answer gave me the direction that I need to be able to solve this. I have posted the code that I used to solve this below.
Solved tests: Birkner's version (recommended)
Solved tests: piped version
Changed source:
WHY: What happens is, with Birkner's library, you can only ever read as much input as you instantiate with the rule originally. If you want to iteratively write to the endpoint, you can do this with a pipe hack, but it doesn't make much of a difference, you can't write to the input over the pipe while the function is actually running, so you might as well use Birkner's version, his #Rule is more concise.
Explanation: In both the pipe hack and with Birkner's code, in the client being tested, multiple calls to create any object that reads from System.in will cause a blocking problem where, once the first object has opened a connection to the Pipe or to System.in, others can not. I don't know why this exactly is for Birkner's code, but with the Pipe I think that it's because you can only open 1 stream to the object-ever. Notice that if you call close on the first buffered reader, and then try to reopen System.in in your client code after having called it from the test, then the second attempt to open will fail because the pipe on the writer's side has been closed as well.
Solution: Easy way to solve this, and probably not the best because it requires modifying the source of the actual project, but not in a horrendous way (yet). So instead of having in the source of the actual project multiple BufferedReader creations, create a buffered reader, and pass the same reader reference around or make it a private variable of the class. Remember that if you have to declare it static that you should not initialize it in a static context because if you do, when the tests run, System.setIn will get called AFTER the reader has been initialized in your client. So it will poll on all readLine/whatever calls, just as it will if you try to create multiple objects from System.in.
Notice that to have your reads segregated between calls from your reader, in this case BufferedReader, you can use newlines to segregate them in the original setup. This way, it returns what you want in each call in the client being tested.
I have a method that writes to a file with a given name. Do I have to test this method and, if so, for what should I test it?
public void record(Object o){
try{
FileWriter fileStream = new FileWriter("data.txt", true);
BufferedWriter out = new BufferedWriter(fileStream);
out.write(o.toString());
out.newLine();
out.close();
} catch (Exception e){
System.err.println("Error: " + e.getMessage());
}
}
Whether you have to test is or not is a question for your project lead. If it's determined you should write some tests, then I would test at least these cases
Happy path (write a good object, check the file contents afterwards)
What happens with a null argument (file exist? what's in it? Does it get closed?)
What happens if the method is called multiple times?
What happens if the file already exists, but is not writeable
The answer to the question "Should I test this?" is always "YES". Now, you might not be able to, or might not know how to, or have the time to, or be allowed to, or want to, but that doesn't change the answer.
Tests are always welcome, but in this case thorough code review might be beneficial. It is hard to write a test that will discover that:
out might not be closed properly, causing file descriptors to leak, i.e. when o.toString() throws an exception
if it throws an exception, the stack trace will get lost (incorrect exception handling)
how should the method behave if the Object o does not override toString() should it care?
A couple more code review suggestions: out.close() should be in a finally block (with its own try/catch), you might want to check the input parameter for sanity, you might want to check if the file already exists and is writable. Also, what happens if o is a String with its own newlines?