I am using Junit 4 and Mockito and I want to stub a method call so that it throws an exception:
doThrow(MyException.class).when(myObject).foo();
The problem is, MyException is a checked exception, so the call to foo() in this statement causes the compiler to complain that I must either handle the exception or add a throws clause to my method.
So I am wondering what the right way to handle this situation is? My thoughts so far have been:
I am using it wrong and there is a better way to do it.
I just add throws MyException to the test method
I extract the call out to another method that just swallows the exception
e.g.
private void givenFooThrowsAnException(MyObject myObject) {
try {
doThrow(MyException.class).when(myObject).foo();
} catch (MyException e) {
// Required to stub a checked exception
}
}
While the stubbing forces you to handle the checked exception, it will actually never throw that exception. The most elegant approach is to declare the test method to throw that exception.
There is only one caveat with that approach. If your test actually verifies that the checked exception is thrown by declaring it in the #Test annotation.
#Test(expected=MyException.class)
public void test...() throws MyException {
//...
}
In that case if your stubbing gets messed up and does throw the checked exception, it may yield a passing test that probably should have failed.
Alternatively you could simply use unchecked exceptions.
Related
I'm creating an integration test:
#RunWith(CdiRunner.class)
#AdditionalClasses({FollowUpActivityRepository.class, SettingsPropertiesProducer.class})
public class FollowUpActivityFeaturesTest {
#Inject protected FollowUpActivityService fuaService;
#Test
public void DigitalInputTOFollowUpActivityFIELDS()
{
FollowUpActivityDTO dto = new FollowUpActivityDTO();
dto.setId("id");
dto.setTimestamp(Date.from(Instant.now()));
dto.setDueTimestamp(Date.from(Instant.now()));
dto.setClosingTimestamp(Date.from(Instant.now()));
dto.setMatter("matter");
dto.setComment("comment");
this.fuaService.createOrUpdate(dto);
}
}
createOrUpdate is like:
public void createOrUpdate(FollowUpActivityDTO dto) throws RepositorySystemException
So, I need to check this exception is NOT thrown.
I'd like to do it elegantly.
Actually, I'm using junit 4.12 and hamcrest 2.0.0.0.
Any ideas?
Example
In .NET, I'm using NSubstitute in order to get that:
this.apiClient.Invoking(c => c.GrantAuthorization()).ShouldNotThrow();
Edit after you reversed the meaning of the question:
If you want your test to fail if an Exception is thrown, you have nothing more to do than just declare an Exception in the throws part of the test method signature (this is not mandatory if the Exception thrown is some kind of RuntimeException, but yours obviously isn't):
public void DigitalInputTOFollowUpActivityFIELDS() throws Exception
No need to specify any kind of Exception. Anyway, any jUnit test will fail as soon as an unhandled Exception is thrown (which is the behavior you're expecting).
From this blog:
Test methods that declare that they throw one particular type of
exception are brittle because they must be changed whenever the method
under test changes.
Old answer:
Just write your test annotation like this:
#Test(expected=RepositorySystemException.class)
This way, the test method will succeed as soon as this exception is thrown.
See javadoc.
Edit after your comment:
To validate the test against any Exception, just:
#Test(expected=Exception.class)
But as B. Dalton suggested, that seems kind of dangerous, as this test would then pass on any Exception, no matter if it's the one you're expecting or any other.
For the sake of completeness, you can also do something like this (based on this answer):
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void DigitalInputTOFollowUpActivityFIELDS()
{
FollowUpActivityDTO dto = new FollowUpActivityDTO();
dto.setId("id");
dto.setTimestamp(Date.from(Instant.now()));
dto.setDueTimestamp(Date.from(Instant.now()));
dto.setClosingTimestamp(Date.from(Instant.now()));
dto.setMatter("matter");
dto.setComment("comment");
thrown.expect(Exception.class);
thrown.expectMessage("something you can check"); // if needed
this.fuaService.createOrUpdate(dto);
}
This way, createOrUpdate will still be able to validate the test by throwing any kind of Exception, but at least the rest of the method won't.
See javadoc for ExpectedException.
Or, of course, the good old solution:
try {
this.fuaService.createOrUpdate(dto);
fail("this should throw an exception");
} catch (RepositorySystemException e){
// pass
} catch (Exception e){
// pass
}
This is less elegant, but allows you to tweak the exception handling as you need.
This is a simplified class that describes my problem:
public class Main {
enum Test{
First(method()){ // Unhandled exception type Exception
// ...
};
Test(Object obj){
//...
}
}
static Object method() throws Exception{
// ...
if (someCondition){
throw new Exception();
}
}
}
Above someCondition depends on device and some situations and I can not decide in about it now, also as you can see, I do not want to catch Exception in method.
Yes. It is a compilation error.
No. There is no special syntax to deal with this.
I do not want to catch Exception in method.
Unfortunately if you throw a checked exception, it has to be caught further up the call stack. That is a fundamental design principal for the Java language, and one that the compiler enforces strictly.
In this, case there is no way to catch the checked exception. Hence, if you are going to call a method in enum constant parameter (as per your code), the method cannot throw a checked exception1.
Here is a possible workaround, though this is probably a bad idea:
public class Main {
enum Test{
First(methodCatchingException()){
// ...
};
Test(Object obj){
//...
}
}
static Object method() throws Exception{
// ...
if (someCondition){
throw new Exception();
}
}
static Object methodCatchingException() {
try {
return method();
} catch (Exception ex) {
throw new SomeRuntimeException("the sky is falling!", ex);
}
}
}
Another way to look at this problem is to ask yourself what should happen with the exception if the compiler let you write that ... and an exception was thrown? Where would it go?
You can't catch it ... because the enum initialization is like a static initialization.
If the Java runtime completely ignored the thrown exception, that would be really bad.
If the Java runtime crashed, then the model of checked exceptions is broken.
So, what this is saying to me is that the Java language design is right, the Java compiler is right ... and the real problem here is in your application design:
You should not be propagating a checked exception here. If an exception occurs in this context it is categorically NOT a recoverable error.
Maybe it is inadvisable to use an enum for this ... because of the potential for non-recoverable initialization errors.
(Note that if this method call terminates due to an unchecked exception, it will turn it into an ExceptionInInitializerError. In addition, the JVM will mark the enum class as uninitializable, and will throw an NoClassDefFoundError if your application attempts to use it; e.g. via Class.forName(...).)
I assume that Exception is used here for illustration purposes. It is a bad thing to declare methods as throws Exception or to throw new Exception(...)
1 - I had a look at the JLS for something to back this up. As far as I can tell, the spec does not mention this situation. I'd have expected to see it listed in JLS 11.2.3. However, it is clear that a compiler cannot allow a checked exception to propagate at that point as it would "break" the model of how checked exceptions work.
I don't think you want to be throwing a checked exception here (which is what Exception is). The reason: you're invoking the call of method inside of the constructor of Test. There's really not a clean way to deal with it.
While the obvious choice here is to switch to RuntimeException, I want you to reconsider throwing the exception in the first place. Since your enum will only ever have First declared in it, does it really make sense for it to throw an exception when it's being instantiated? Personally, I don't think it does; whatever dangerous operation it's doing should be deferred until you want to invoke it, and then would you want to throw your exception.
#Test
public void testA() throws Exception {
}
Is above a good style to code ? Because the test is allowed to throw exceptions and if the code throws exception, then Netbeans consider that as a successful test case.
If yes, then I want to make the test fail if it throws any exception, how can I do that ?
Your code is perfectly valid if you want the test to fail if any exception occurs. Imho this is good style if a checked exception may be thrown in the test code, but should not occur.
If you wish to test exception generation on a specific line or wish to verify something on the exception itself, this pattern is usually more helpful:
#Test
public void testA() {
// Initialize
try {
// Except Exception here
Assert.fail("Exception not thrown");
} catch (IWantToCatchException ex) {
// Assert exception is correct
}
// other code
}
To pass a test when an exception is thrown you need to set the expected element of the Test annotation.
#Test(expected=Exception.class)
Otherwise jUnit will fail the test if an exception is thrown, which may be appropriate in your case.
Since JUnit 4.7 there is the expected part in the annotation of tests:
#Test(expected=YourException.class)
With this the test succeeds only if the exception is thrown.
Therefore, if you leave expected out, the test fails whenever an exception is thrown.
Exceptions are the rare cases which you don't know will happen or not, but you take precautions. But in case of unit testing if you are assured of that it will throw certain exception then test it that way like :
#Test(expected = ArithmeticException.class)
public void testA() {
int i = 1/0;
}
Is it possible to throw an exception without catching it?
Example
public void foo() throws SomeException{
// ....
if (somethingCatestrophic) throw new SomeException();
// ....
}
Now I want to call foo, but don't want to catch any errors, as the exceptions should never been thrown at runtime (unless there's a bug)
Unless it is something you are planning for and recovering from locally, it is probably best in this case to use an unchecked exception, e.g., a RuntimeException derivative.
Why don't you catch it inside the method?
Simply use try catch block and go on, if the exception is insignificant and doesn't influence any behaviour of your program.
You can avoid catching an exception, but if there is an exception thrown and you don't catch it your program will cease execution (crash).
There is no way to ignore an exception. If your app doesn't need to do anything in response to a given exception, then you would simply catch it, and then do nothing.
try {
...some code that throws an exception...
} catch (SomeException ex) {
// do nothing
}
NOTE: This is often considered bad style, however, and people may tell you so. The often-cited reason is that, even if you're not going to do anything with the exception, that in most cases you should at least log it somewhere, notify the user, or take some other appropriate action depending on what you app is doing, and what caused the exception in the first place. If you're not sure why an exception is being thrown (maybe it's a bug you haven't solved yet), then generally you should at least log it so you can figure it out later.
If SomeException is a checked exception, the method that calls foo() will either have to catch that exception and deal with it or also be declared to throw SomeException or a parent of it.
If SomeException is a runtime exception, then methods that call it will not need to catch it.
There is a trick, You can play with generics.
/**
* A java syntax glitch to throw any throwable without the need to catch it.
*
* #param throwable to be ignite
* #param <T> the type of the throwable to trick the compiler that it's the one thrown
* #throws T exactly the given throwable
*/
public static <T extends Throwable> void ignite(Throwable throwable) throws T {
Objects.requireNonNull(throwable, "throwable");
throw (T) throwable;
}
This test should pass
#Test(expected = IOException.class)
public void ignite() {
ignite(new IOException());
}
Eclipse's CodePro generates JUnit tests, however, all test methods that it generates throw Exception even if it is impossible for a checked exception to be thrown. Is this a limitation of CodePro, or a good JUnit practice I haven't seen before?
For example:
#Test
public void testCategory_1()
throws Exception {
String categoryName = "";
Category result = new Category(categoryName);
// add additional test code here
assertNotNull(result);
assertEquals(null, result.getCategoryName());
}
Where new Category(String) and result.getCategoryName() don't throw any checked exceptions.
In the case above, you can remove the throws Exception with no problems. However, in the case where you do have an checked Exception, the code becomes much simpler to manage if you just add the throws Exception. Look at the alternative:
#Test public static void testIt() {
try {
foobar(); // throws an IOException
} catch (Exception e) {
fail("caught an exception " + e.getMessage());
}
}
as opposed to:
#Test public static void testIt() throws IOException {
foobar();
}
JUnit handles Exceptions exactly the same as assertion failures (which is actually implemented as an AssertionError), so if there is an unexpected exception in your code it will result in a failed test, which is probably what you want. And your test is much clearer
If you have an expected exception, then you can either specify it as expectedException in the #Test annotation or using a TestRule ExpectedException.
I use this a lot when I have checked exceptions in my code. It's a lot easier to add throws Exception to your test method rather than a list of all of the checked Exceptions. You do fall foul of some checkstyle rules though :-)
Good practice? Rather acceptable practice. It makes maintenance of tests a lot easier, and the code slightly clearer.
It definitely is not a limitation. When you write a unit test you don't really care what kind of exception is thrown. Outside of expected exceptions, any exception will result in a red bar telling you that something is not OK. Therefore it is sufficient to have a "catch all" throws Exception clause.
You don't have to throw Exception, and I would imaging that tool could have performed the static analysis to determine if a checked exception could have been thrown. However, when I write unit tests by hand I typically add the throw clause because invariably I add a line of code that does throw a checked exception.