Java: Junit4: Exception testing not working, insists on try-catch block: - java

My Test: this is where it underlines the stuff after sax. and insists that I have a try-catch block.... but the internet says that the proper way to test for exception is #Test(expected=IllegalArgumentException.class)
#Test(expected= XMLClientNotFoind.class)
public void testGetClientFromIP() throws XMLClientNotFound{
...
assertEquals(c, sax.getClientFromIP("101.0.2.01"));
}
And the method, getClientFromIP is here:
public Client getClientFromIP(String ip) throws XMLClientNotFound {
...
throw new XMLClientNotFound();
}
And my exception:
public class XMLClientNotFound extends Exception{
}

First of all:
#Test(expected=IllegalArgumentException.class)
should not be considered as a proper way, especially with such a generic exception. The reason is that you have no control over which statement in your test method actually threw the exception. Also you can't make any assertions on the message label, cause, etc.
Using try-catch precisely surrounding a line that is suppose to throw an exception is the right way to go:
try {
shouldThrow()
fail("Expected exception");
} catch(XMLClientNotFound e) {
assertThat(e).hasMessage("Expected message"); //FEST-Assert syntax
}
You might also try JUnit #Rule that I wrote some time ago to make your test more readable.

You still need to define throws clause for checked exceptions. #Test(expected=...) part just says JUnit that you expect your test case to throw that exception(s).

Is it possible you have other code in the test method that throws a different exception?
For example...
#Test(expected= XMLClientNotFoind.class)
public void testGetClientFromIP() throws XMLClientNotFound{
thisMethodThrows_ExceptionX();
assertEquals(c, sax.getClientFromIP("101.0.2.01"));
}
In the above case the compiler would complain because you are not handling ExceptionX. You would either have to surround with try/catch or say throws ExceptionX in test method signature as well.
In general it is a good idea to test one thing in a test method. I do not understand the assertion if you are expecting the method to throw an exception; there is nothing to assert since it is not going to return anything.

Related

Try catch in a JUnit test

I'm writing unit tests for an application that already exists for a long time. Some of the methods I need to test are build like this:
public void someMethod() throws Exception {
//do something
}
If I want to test these methods I have to write something like this in my unit test:
#Test
public void someTest() {
try {
someMethod();
}
catch (Exception e) {
e.printStackTrace();
}
}
Is it a good practice to do this? Or is there an other way to test these methods?
I did some research on the internet and I found a few solutions with the #Rule annotation and #Test(expected=Exception.class), but that's not working (Eclipse keeps showing the someMethod() line in the test as wrong).
I don't know if these are good solutions, because I'm pretty new to the whole unit testing story.
If someone who knows a lot about this could help me out, I would be really thankful.
Since Exception is a checked exception, you either:
Have to catch the exception in a try...catch statement, or
Declare the exception to be thrown in the method itself.
What you have up there works fine, but my personal preference is to declare the exception to be thrown. This way, if an exception I'm not expecting is thrown during the run of the test, the test will fail.
#Test
public void someTest() throws Exception {
// dodgy code here
}
If we need to see if a specific exception is thrown, then you have the option of using #Rule or adding the value to the #Test annotation directly.
#Test(expected = FileNotFoundException.class)
public void someTest() throws Exception {
// dodgy code here
}
In JUnit 5, you can leverage Assertions.assertThrows to accomplish the same thing. I'm less familiar with this overall since it's not yet GA at the time of editing, but it appears to accept an Executable coming from JUnit 5.
#Test
public void someTest() {
assertThrows(FileNotFoundException.class, () ->
{ dodgyService.breakableMethod() };
}
#Test
public void someTest() {
try {
someMethod();
}
catch (Exception e) {
Assert.fail("Exception " + e);
}
}
Is what you can do, if the exception should not occur. An alternative would be to throw the exception in the signature like this:
#Test
public void someTest() throws Exception {
someMethod();
}
The difference is, that in one case the test will fail with an assertion exception and in the other case it will fail because the test crashed. (like somewhere in your code you get a NPE and the test will because of that)
The reason you have to do this, is because Exception is a checked exception. See Checked versus unchecked exception
The #Test(expected=Exception.class) is for tests, that want to test that the exception will be thrown.
#Test(expected=ArrayIndexOutOfBounds.class)
public void testIndex() {
int[] array = new int[0];
int var = array[0]; //exception will be thrown here, but test will be green, because we expect this exception
}
Do not catch your application's exception in your test code. Instead, declare it to be thrown upwards.
Because, when JUnit's TestRunner finds an exception thrown, it will automatically log it as an error for the testcase.
Only if you testcase expects that the method should thrown an Exception you should use #Test(expected=Exception.class) or catch the exception.
In other cases, just throw it upwards with,
public void someTest() throws Exception {
You can add exception in test method signature. Then, if you are testing whether exception is thrown, you have to use #Test(expected=Exception.class). In the test cases where exception has not to be thrown, test will pass successfully.
#Test
public void testCaseWhereExceptionWontBeThrown() throws Exception {
someMethod(); //Test pass
}
#Test(expected = Exception.class)
public void testCaseWhereExceptionWillBeThrown() throws Exception {
someMethod(); //Test pass
}
There are two main rules on how to process exceptions at Junit testers:
If the exception was originated into the tested code:
If it was expected, declare it in the expected attribute of the Test annotation. Or, if further checks should be done on the exception object itself, catch it and ignore it. (In this case, there must be also a call to Assert.fail at the end of the try block, to indicate that the expected exception was not produced).
If it was not expected, catch it and execute Assert.fail. (A previous call to Exception.printStackTrace is also useful).
If the exception was not originated into the tested code or it is not interesting to the test (for example, most of the IOExceptions are produced at network level, before the test could even be completed), rethrow it at the throws clause.
Why you should expect an exception in the tester? Remind: You should code one test method for every possible result on the tested code (in order to achieve a high code coverage): In your case, one method that must return successfully, and at least another one that must produce an Exception.
Three points about JUnit:
Tests should be precise, they should pass or fail unambiguously based solely on how the test inputs are set up.
Tests should have failures reported back into the framework.
Tests should not rely on having their output read.
Your example fails on all three counts. If an exception gets thrown or not, the test still passes. If an exception is thrown JUnit never finds out about it and can't include it in the test results. The only way to know something went wrong is to read what the test writes to stdout, which makes errors too easy to ignore. This is not a useful way to write tests.
JUnit was designed to make doing the right thing easy and to give developers useful feedback. If an exception gets thrown from a test method, it gets caught by the framework. If the test was annotated with an exception indicating that exception is expected, then the framework marks the test as passing. Otherwise the framework fails the test and records the stacktrace for reporting. The framework reports what assertions fail and what unexpected exceptions occurred so that everybody knows if the tests worked or not.
If you expect a test to succeed without throwing an exception, then if anything in the test can throw a checked exception, add throws Exception to the test method signature. Adding the throws to the signature doesn't say the method has to throw anything, it just lets any exceptions that happen to occur get thrown so that the test framework can catch them.
The only instance where you would actually catch the exception in the test is where you want to test assertions about the exception; for instance, you could test that the message on the exception is what you expect, or if the exception has a cause set on it. In that case you would add Assert.fail() at the end of the try-block so that not having an exception thrown will cause the test to fail.
It isn’t having a try-catch block that is so bad, it’s the absence of anything that will cause the test to fail that is bad.
When you write a test at first, make it fail. That way you prove to yourself that you know what the test is doing, and you confirm that, when there is a failure, you will be made aware of it.
What kind of exception is it? Is it
an exception from doing something like using streams that won't happen in your unit test or
an exception that can happen because of some kind of bad input?
If it's 1. I would just put it at the method signature level because a try-catch is serving no real purpose other than ceremony.
#Test
public void testFoo() throws Exception {
// ...
}
If it's 2. it becomes a little more complicated. You need to ask yourself what should be happening if the Exception is thrown. Should the test fail? Is it expected? Is it irrelevant? Examples below of how to handle all of these. BEWARE: I only used Exception because you did. I hope it really isn't though because if it's possible for some other exception to be thrown other than the expected then these will be very wonky. If possible don't use Exception, use something more specific (in the junit and code).
// The below code assumes you've imported the org.junit.Assert class.
#Test
public void thisShouldFailIfExceptionCaught() {
//Given...
try {
// When...
} catch (Exception e) {
Assert.fail();
}
// Then...
}
#Test
public void thisShouldPassOnlyIfTheExceptionIsCaught() {
//Given...
try {
// When...
Assert.fail();
} catch (Exception expected) {}
// No "then" needed, the fact that it didn't fail is enough.
}
#Test
public void irrelevantExceptionThatCouldBeThrown() {
//Given...
try {
// When...
} catch (Exception e) {}
// Then...
}

Managing checked exceptions in different JUnit tests

I am writing a Java Unit test for one of my method. The method declaration is like this:
public int convertToInteger() throws InvalidRomanNumberException
{
int result=0;
BaseRomanNumeral num1, num2;
int i=0;
if(!validOperation())
throw new InvalidRomanNumberException();
}
Now I am trying to write two unit tests. One is to test if the right exception is thrown. Another one is to make sure that that the write conversion happens. This is how my test case looks
#Test
public void testRomanNumberConversion() {
String romanValue="MCMII";
RomanNumber num=new RomanNumber(romanValue);
assertEquals(1903,num.convertToInteger());
}
#Test(expected = InvalidRomanNumberException.class)
public void testInvalidRomanNumberExceptionThrown() {
String romanValue="MCMIIII";
RomanNumber num=new RomanNumber(romanValue);
num.convertToInteger();
}
For both these test cases I am getting an error saying Unhandled InvalidRomanNumberException. This is resolved only when I add throws InvalidRomanNumberException to each method definition. But I don't think that is the right way. Just want to check with the rest of you, what is the norm here? How should I resolve this unhandled exception message
Since it looks like InvalidRomanNumberException is a checked exception, you have to either surround it with a try-catch or declare that the method throws InvalidRomanNumberException. JUnit or not, this is the norm.
That being said, the test case method that you expect will throw a InvalidRomanNumberException should ideally declare that it throws one since there is no point suppressing it with a try-catch as your test case will fail. On the other hand, the test case method that you expect will not throw an exception can use a try-catch around the convertToInteger method and regardless of whether an exception is thrown, this test case should have an assert on the expected result from convertToInteger method.
The end result of a JUnit test case should be whether the test passed or failed. An exception at runtime would indicate neither. A JUnit test case must not crash.
This feels more like it should be an unchecked exception as opposed to a checked exception.
Recall the difference between the two: a checked exception is meant to be something that's reasonably recoverable from, like a missing file or a malformed URL. An unchecked/run time exception is meant to be something that is irrecoverable, like dividing by zero.
If a user enters in an invalid Roman numeral, it might not make sense to say that they can recover and try again - the conversion layer shouldn't be responsible for that. It sounds more like a thing should be decided at instantiation time.
If you instead make your custom exception extend RuntimeException, then you won't need to declare it to be thrown (and if you did, it wouldn't have any effect), and you won't have to deal with it in your tests.
The alternative would be to declare it to be thrown in your tests instead. This has the advantage of allowing you to keep these exceptions as checked and ensuring that the tests won't complain about you not handling the potential exception from being uncaught or unthrown.
#Test
public void testRomanNumberConversion() throws InvalidRomanNumberException {
String romanValue = "MCMII";
RomanNumber num = new RomanNumber(romanValue);
assertEquals(1903, num.convertToInteger());
}
#Test(expected = InvalidRomanNumberException.class)
public void testInvalidRomanNumberExceptionThrown() throws InvalidRomanNumberException {
String romanValue = "MCMIIII";
RomanNumber num = new RomanNumber(romanValue);
num.convertToInteger();
}

Should jUnit test cases handle default exceptions in a throws declaration or in a try catch block

If I write test cases for a function that throws a bunch of exceptions should I add a throws declaration for these exceptions in my test method or should I catch each individual exception. What is the correct way of going about it? I believe try-catch is a better way but in the catch block should I print the stacktrace?
For example, I have a method getGroups(String name) that throws AuthenticationException. If I write a test case to check if an IllegalArgumentException is being thrown when the name parameter is null, how do I handle the AuthenticationException? Do I add it to throws part of my method or should I enclose the exception in a try-catch block.
#Test
public void testGetGroupsWithNull() throws AuthenticationException {
thrown.expect(IllegalArgumentException.class);
getGroups(null);
}
In the above test case I just added a throws AuthenticationException, but I would like to know if it is better to enclose the exception in a try-catch block and what shoudld I do after catching the exception. I could print the stack trace.
I am handling the unexpected exception AuthenticationExceptionby not placing it in the 'throws' clause but in a try/catch block.
#Test
public void testGetGroupsWithNull() {
thrown.expect(IllegalArgumentException.class);
try {
getGroups(null);
} catch(AuthenticationExcption e) {
Assert.fail("Authentication Exception");
}
}
JUnit has a great article here: https://github.com/junit-team/junit/wiki/Exception-testing on this very subject.
You can do:
#Test(expected= IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
or:
#Test
public void testExceptionMessage() {
try {
new ArrayList<Object>().get(0);
fail("Expected an IndexOutOfBoundsException to be thrown");
} catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
}
}
If a JUnit test throws an unexpected exception, it fails. That is the behaviour that you want. So there's no point in EVER using a try/catch block. If you're expecting an exception, use an ExpectedException rule (which you obviously know about, from your code snippet). But whether you're expecting one or not, don't use try/catch.
This means that if your exception is a checked exception, you need a throws clause. In fact, you'll often need a throws clause on your test method, even when you're NOT expecting the exception to be thrown, just because your test calls a method that can SOMETIMES throw a checked exception. I have got into the habit of writing throws Exception on every single test method. There is no reason not to; and it's just one less thing to worry about.
The annotation is more communicative.
It signals what the test expects to happen without forcing the reader to read the code.
Any single test should only expect a single exception to be thrown, because each test should be testing a single behavior. A single behavior can only throw one exception.
If any other exception is thrown it's a test failure. The test method signature must reflect any possible checked exceptions, of course, as would real code calling that same method.
Using the rule of writing as little code as possible to solve the problem, your first code snippet wins. So yes, put the AuthenticationException into your test method's throws clause. It is more succinct and readable.
I've just looking for the same question since I'm dealing with your topic and I found a good explanation for unit test best practices. A little extraction from the article can help you.
It is unnecessary to write your own catch blocks that exist only to fail a test because the JUnit framework takes care of the situation for you. For example, suppose you are writing unit tests for the following method:
final class Foo {
int foo(int i) throws IOException;
}
Here we have a method that accepts an integer and returns an integer and throws an IOException if it encounters an error. Here is the wrong way to write a unit test that confirms that the method returns three when passed seven:
// Don't do this - it's not necessary to write the try/catch!
#Test
public void foo_seven()
{
try
{
assertEquals(3, new Foo().foo(7));
}
catch (final IOException e)
{
fail();
}
}
The method under test specifies that it can throw IOException, which is a checked exception. Therefore, the unit test won't compile unless you catch the exception or declare that the test method can propagate the exception. The second alternative is preferred because it results in shorter and more focused tests:
// Do this instead
#Test
public void foo_seven() throws Exception
{
assertEquals(3, new Foo().foo(7));
}
We declare that the test method throws Exception rather than throws IOException. The JUnit framework will make sure that this test fails if any exception occurs during the invocation of the method under test - there's no need to write your own exception handling.
You can find more about JUnit best practices like above in this article:
http://www.kyleblaney.com/junit-best-practices/
Hope to help.

How to combine logging and unit-testing in java?

I've just started my very first toy-project in java and faced with misunderstanding of how it should be done. I'm using java.util.logging and JUnit4 library.
For example we have something like this:
public class SomeClass {
private static Logger log = Logger.getLogger(SomeClass.class.getName());
public static void SomeMethod() {
try{
...some code...
} catch(Exception e){
log.warning("Something bad happened");
}
}
And the unit-test will be:
#Test
public void SomeClassTest(){
SomeClass.SomeMethod();
}
But there will never be an exception, cause I've already handled it in method.
Should I generate new exception in catch-block? Or may be using junit combined with logging is not a good idea?
A method that does not throw an exception (and returns the expected value if any) is meant to work correctly from the perspective of a user.
So you should use try - catch and logging inside a method, when you can catch an exception and the method will still work correctly (do something else when this error happens for example but still return the expected result or perform the supposed operation).
In this case the unit test should check if the operation was performed correctly (if the object is in the expected state and the result value (in your case void) is correct
You should rethrow the exception (and usually not log it, but that depends) if the method cannot do what it is supposed to do when the exception occurs.
In this case the unit test should check if the operation was performed correctly (if the object is in the expected state and the result value (in your case void) is correct if there is no exception, and if there is an exception it should check if this exception was expected
If you want to test that the exception is thrown then you would have to re-throw, or not catch, the Exception.
Otherwise you can unit test that the class is in the correct state after the exception, i.e. that the exception was correctly handled.
I would say one other thing. Don't catch(Exception e), catch the specific exception you are expecting. Otherwise you will handle other, unexpected, exceptions in the same way and that is really quite dangerous.
You can simply rethrow the caught exception:
public class SomeClass {
private static Logger log = Logger.getLogger(SomeClass.class.getName());
public static void SomeMethod() {
try {
// your stuff
} catch (Exception e) {
log.warning("Something happened");
throw e;
}
}
}
Should I generate new exception in catch-block?
No. don't do that! you can test your existing code! when you only want to log the message but you don't want to handle it in the method that call someMethod() don't throw it!
using junit combined with logging is not a good idea?
both are good ideas and can be used together without problems.
Think about how you can test your method. i would not modify the code just that you can easily test it. because you WANTED to catch the exception and log for a reason.
try verifing what variables or objects are modified in your test-method

Testing Exceptions of a method with EasyMock

I am newbie to unit testing. I am using TestNG with MyEclipse to develop unit test cases for my application. While doing it I am facing some problems with EasyMock. Here is my code (Name of the class, method names and return types are changed for security reasons but you will get a clear idea what I am trying to achieve here).
public MyClass
{
// This is a method in my class which calls a collaborator which I
// want to mock in my test case
public SomeObject findSomething(SomeOtherObject param) throws Exception
{
SomeOtherObject param a = myCollaborator.doSomething(param);
// Do something with the object and then return it
return a;
}
}
Now here is my test. Now what I actually want to achieve in my test
case is that I want to check that my function (findSomething) properly
throws exception in case some exception is thrown. In future some
other developer can change the signature (throws Exception isn't
really part of method signature) of the method and remove the throws
Exception from my method. So how can I make sure that nobody changes
it?
#Test(dataProvider="mydataProvider", expectedExceptions=Exception.class)
public void MyTest(SomeOtherObject param) throws Exception {
{
EasyMock.expect(myCollaboratorMock.doSomething(param)).andThrow(new Exception());
EasyMock.replay(myCollaboratorMock);
}
I am getting exception
"java.lang.IllegalArgumentException: last
method called on mock cannot throw java.lang.Exception"
What I am
doing wrong here? Can someone shed some light on how to write a test
case for my particular scenario?
The collaborator's doSomething() method doesn't declare that it may throw Exception, and you're telling its mock to throw one. It's not possible.
Exception is a checked exception. It can only be thrown if it's declared in the method signature. If the method has no throws clause, all it can do is throwing runtime exceptions (i.e. RuntimeException or any descendant class).

Categories

Resources