I am using Mockito to mock some objects and test my WebSocket message sender service. The send method takes a org.springframework.web.socket.WebSocketSession and a message, and returns a CompletableFuture.
In the lambda passed to the thenAccept() method of the CompletableFuture, I verify that the session.sendMessage() method has been called with the expected value :
WebSocketSession session = mockWebSocketSession();
TextMessage expectedMessage = new TextMessage("test text message");
sender.sendStringMessage(session, "test text message").thenAccept(nil -> {
try{ // this is what I am talking about
verify(session).sendMessage(expectedMessage);
}catch(IOException e){}
});
Since the sendMessage() method throws an IOException I am forced to add a useless try/catch block around the call on the inside the lambda. It is needlessly verbose.
How could I avoid it ?
You can try using Durian library
foodOnPlate.forEach(Errors.suppress().wrap(this::eat));
list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));
or extend Cosumer yorself
#FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {
#Override
default void accept(final T elem) {
try {
acceptThrows(elem);
} catch (final Exception e) {
/* Do whatever here ... */
System.out.println("handling an exception...");
throw new RuntimeException(e);
}
}
void acceptThrows(T elem) throws Exception;
}
//and then pass
thenAccept((ThrowingConsumer<String>) aps -> {
// maybe some other code here...
throw new Exception("asda");
})
I would rework you test in this way
final String testMessage = "test text message";
WebSocketSession session = mockWebSocketSession();
sender.sendStringMessage(session, testMessage).get(); // will wait here till operation completion
verify(session).sendMessage(new TextMessage(testMessage));
and add IOException to the test method signature.
This solution solves 2 issues:
you test code is cleaner and all you assertions and verifications are at the end of your test method in one place;
the solution solves race condition when you test may finish silently and green but your vitrification in CompletableFuture lambda even been executed
Follow on from my comment, I'll do something like this :
public void myMethod() {
try{ // this is what I am talking about
verify(session).sendMessage(expectedMessage);
}catch(IOException e) {}
}
And then :
sender.sendStringMessage(session, "test text message").thenAccept(nil -> myMethod());
duplicate of this ?
Java 8: Mandatory checked exceptions handling in lambda expressions. Why mandatory, not optional?
you are in test class, so just add throws IOException to your method. that way if this method raised IOException in which case it means your test will fail.
or you can also say that your method is expected to throw IOException,
something like :
#Test(expected = IOException.class)
public void yourTestCaser(){
//...
with that , it could look like this :
sender.sendStringMessage(session, "test text message").thenAccept(nil ->
{ verify(session).sendMessage(expectedMessage); });
Related
How do you throw an exception inside a lambda e.g in ifPresentOrElse of a Optional?
try {
foo.bar(baz).ifPresentOrElse(theBar -> {
// A code inside here needs to throw a custom exception so the outside can handle it
// It can't throw atm, and it is an unhandled exception here
}, () -> { response.set(notFound()); }
} catch(CustomException e) {
somethingImportantWhenExceptionIsThrown();
}
Altough not explicitly mentioned in your question, i am going to assume that you intent to throw a checked exception from ifPresentOrElse.
First, you should try to understand why you cannot throw an exception. The Consumer interface has, as Runnable, only a single abstract method, which makes it a #FunctionalInterface. From the documentation:
Note that instances of functional interfaces can be created with
lambda expressions, method references, or constructor references.
This is a reduced version of the Consumer interface:
public interface Consumer<T> {
void accept(T t); // <-- NO throws Exception
}
Alternatively, you can still use the old anonymous inner class:
Consumer<Object> consumer = new Consumer<>() {
#Override
public void accept(Object o) { // <-- NO throws Exception
// consume
}
};
Therefore, you cannot throw a checked exception from the accept method. It is not possible by design. You can, however, chose one of the following options:
Use a custom ThrowingConsumer and ThrowingOptional class, which can throw exceptions (since you declare them in their method signatures), not recommended.
Wrap the checked exception in a RuntimeException, which does not need to be declared in the method signature, and can therefore be thrown.
Rewrite your code to not use the lambda expression.
Example, for the last point:
Optional<Bar> barOpt = foo.bar(baz);
if(bar.isPresent()) {
Bar bar = barOpt.get();
try {
// code that throws checked exception
} catch(CustomException e) {
somethingImportantWhenExceptionIsThrown();
}
} else {
response.set(notFound());
}
The solution for this is to use Project Lombok:
And have the method wrapping this function annotated with SneakyThrows, as such:
#SneakyThrows
void method() {
try {
foo.bar(baz).ifPresentOrElse(theBar -> {
throw()
}, () -> { response.set(notFound()); }
} catch(CustomException e) {
somethingImportantWhenExceptionIsThrown();
}
}
You can do it with apache commons-lang3 library.
https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/function/Failable.html
Optional.of(obj).ifPresentOrElse(Failable.asConsumer(theBar -> {
throw new Exception();
}), () -> {});
Suppose I have a class and a method
class A {
void foo() throws Exception() {
...
}
}
Now I would like to call foo for each instance of A delivered by a stream like:
void bar() throws Exception {
Stream<A> as = ...
as.forEach(a -> a.foo());
}
Question: How do I properly handle the exception? The code does not compile on my machine because I do not handle the possible exceptions that can be thrown by foo(). The throws Exception of bar seems to be useless here. Why is that?
You need to wrap your method call into another one, where you do not throw checked exceptions. You can still throw anything that is a subclass of RuntimeException.
A normal wrapping idiom is something like:
private void safeFoo(final A a) {
try {
a.foo();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
(Supertype exception Exception is only used as example, never try to catch it yourself)
Then you can call it with: as.forEach(this::safeFoo).
If all you want is to invoke foo, and you prefer to propagate the exception as is (without wrapping), you can also just use Java's for loop instead (after turning the Stream into an Iterable with some trickery):
for (A a : (Iterable<A>) as::iterator) {
a.foo();
}
This is, at least, what I do in my JUnit tests, where I don't want to go through the trouble of wrapping my checked exceptions (and in fact prefer my tests to throw the unwrapped original ones)
This question may be a little old, but because I think the "right" answer here is only one way which can lead to some issues hidden Issues later in your code. Even if there is a little Controversy, Checked Exceptions exist for a reason.
The most elegant way in my opinion can you find was given by Misha here Aggregate runtime exceptions in Java 8 streams
by just performing the actions in "futures". So you can run all the working parts and collect not working Exceptions as a single one. Otherwise you could collect them all in a List and process them later.
A similar approach comes from Benji Weber. He suggests to create an own type to collect working and not working parts.
Depending on what you really want to achieve a simple mapping between the input values and Output Values occurred Exceptions may also work for you.
If you don't like any of these ways consider using (depending on the Original Exception) at least an own exception.
You might want to do one of the following:
propagate checked exception,
wrap it and propagate unchecked exception, or
catch the exception and stop propagation.
Several libraries let you do that easily. Example below is written using my NoException library.
// Propagate checked exception
as.forEach(Exceptions.sneak().consumer(A::foo));
// Wrap and propagate unchecked exception
as.forEach(Exceptions.wrap().consumer(A::foo));
as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo));
// Catch the exception and stop propagation (using logging handler for example)
as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo)));
I suggest to use Google Guava Throwables class
propagate(Throwable throwable)
Propagates throwable as-is if it is an
instance of RuntimeException or Error, or else as a last resort, wraps
it in a RuntimeException and then propagates.**
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
throw Throwables.propagate(e);
}
});
}
UPDATE:
Now that it is deprecated use:
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
});
}
You can wrap and unwrap exceptions this way.
class A {
void foo() throws Exception {
throw new Exception();
}
};
interface Task {
void run() throws Exception;
}
static class TaskException extends RuntimeException {
private static final long serialVersionUID = 1L;
public TaskException(Exception e) {
super(e);
}
}
void bar() throws Exception {
Stream<A> as = Stream.generate(()->new A());
try {
as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo()
} catch (TaskException e) {
throw (Exception)e.getCause();
}
}
static void wrapException(Task task) {
try {
task.run();
} catch (Exception e) {
throw new TaskException(e);
}
}
More readable way:
class A {
void foo() throws MyException() {
...
}
}
Just hide it in a RuntimeException to get it past forEach()
void bar() throws MyException {
Stream<A> as = ...
try {
as.forEach(a -> {
try {
a.foo();
} catch(MyException e) {
throw new RuntimeException(e);
}
});
} catch(RuntimeException e) {
throw (MyException) e.getCause();
}
}
Although at this point I won't hold against someone if they say skip the streams and go with a for loop, unless:
you're not creating your stream using Collection.stream(), i.e. not straight forward translation to a for loop.
you're trying to use parallelstream()
I wrote some test cases to test some method. But some methods throw an exception. Am I doing it correctly?
private void testNumber(String word, int number) {
try {
assertEquals(word, service.convert(number));
} catch (OutOfRangeNumberException e) {
Assert.fail("Test failed : " + e.getMessage());
}
}
#Test
public final void testZero() {
testNumber("zero", 0);
}
If I pass -45, it will fail with OutOfRangeException but I am not able to test specific exception like #Test(Expected...)
An unexpected exception is a test failure, so you neither need nor want to catch one.
#Test
public void canConvertStringsToDecimals() {
String str = "1.234";
Assert.assertEquals(1.234, service.convert(str), 1.0e-4);
}
Until service does not throw an IllegalArgumentException because str has a decimal point in it, that will be a simple test failure.
An expected exception should be handled by the optional expected argument of #Test.
#Test(expected=NullPointerException.class)
public void cannotConvertNulls() {
service.convert(null);
}
If the programmer was lazy and threw Exception, or if he had service return 0.0, the test will fail. Only an NPE will succeed. Note that subclasses of the expected exception also work. That's rare for NPEs, but common with IOExceptions and SQLExceptions.
In the rare case that you want to test for a specific exception message, you use the newish ExpectedException JUnit #Rule.
#Rule
public ExpectedException thrown= ExpectedException.none();
#Test
public void messageIncludesErrantTemperature() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("-400"); // Tests that the message contains -400.
temperatureGauge.setTemperature(-400);
}
Now, unless the setTemperature throws an IAE and the message contains the temperature the user was trying to set, the test fails. This rule can be used in more sophisticated ways.
Your example can best be handled by:
private void testNumber(String word, int number)
throws OutOfRangeNumberException {
assertEquals(word, service.convert(number));
}
#Test
public final void testZero()
throws OutOfRangeNumberException {
testNumber("zero", 0);
}
You can inline testNumber; now, it does not help much. You can turn this into a parametrized test class.
Remove the try-catch block and add throws Exception to your test method, like:
#Test
public final void testZero() throws Exception {
assertEquals("zero", service.convert(0));
}
JUnit expects failing tests will throw Exceptions, your catching them is just stopping JUnit from being able to report them properly. Also this way the expected property on the #Test annotation will work.
You don't need to catch the exception to fail the test. Just let it go (by declaring throws) and it will fail anyway.
Another case is when you actually expect the exception, then you put fail at the end of try block.
For example:
#Test
public void testInvalidNumber() {
try {
String dummy = service.convert(-1));
Assert.fail("Fail! Method was expected to throw an exception because negative numbers are not supported.")
} catch (OutOfRangeException e) {
// expected
}
}
You can use this kind of test to verify if your code is properly validating input and handles invalid input with a proper exception.
There are several strategies that are open to you to deal with expected exceptions in your tests. I think the JUnit annotations and try/catch idiom have already been mentioned above. I'd like to draw attention to the Java 8 option of Lambda expressions.
For instance given:
class DummyService {
public void someMethod() {
throw new RuntimeException("Runtime exception occurred");
}
public void someOtherMethod(boolean b) {
throw new RuntimeException("Runtime exception occurred",
new IllegalStateException("Illegal state"));
}
}
You can do this:
#Test
public void verifiesCauseType() {
// lambda expression
assertThrown(() -> new DummyService().someOtherMethod(true))
// assertions
.isInstanceOf(RuntimeException.class)
.hasMessage("Runtime exception occurred")
.hasCauseInstanceOf(IllegalStateException.class);
}
Take a look at this blog which covers most of the options with examples.
http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html
And this one explains the Java 8 Lambda option more fully:
http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html
I've made an MethodRule and #Rule-annotation to make my test-life a bit easier.
It checks if a specific exception had been thrown and checks if the exception-message equals or contains the given message.
Now when i run a testmethod with more lines to test, it only takes the first line and than is ready. How do I make so all my lines in the testmethod are tested?
This is my code:
Annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface ExpectedDomeinValidatieMessage {
String value() default "";
String contains() default "";
}
MethodRule:
#Override
public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
ExpectedDomeinValidatieMessage message = method.getAnnotation(ExpectedDomeinValidatieMessage.class);
if (message == null) {
base.evaluate();
} else {
try {
base.evaluate();
Assert.fail("DomeinValidatieException not thrown");
} catch (DomeinValidatieException e) {
if (StringUtils.isNotBlank(message.value())) {
if (!e.getMessage().equals(message.value())) {
throwException(e, "", message.value(), e.getMessage());
}
}
if (StringUtils.isNotBlank(message.contains())) {
if (!e.getMessage().contains(message.contains())) {
throwException(e, "Segment niet gevonden:", message.contains(), e.getMessage());
}
}
}
}
}
private void throwException(Throwable exception, String message, String expected, String actual) {
ComparisonFailure cf = new ComparisonFailure(message, expected, actual);
cf.setStackTrace(exception.getStackTrace());
throw cf;
}
};
Usage:
#Test
#ExpectedDomeinValidatieMessage("[Werkzaamheden] WerkzaamMetGevaarlijkeStoffen niet gevuld")
public void valideerWerkzaamMetGevaarlijkeStoffen() throws DomeinValidatieException {
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen(null);
validator.valideer();
}
If I use it like this, it only tests the first test in the method:
#Test
#ExpectedDomeinValidatieMessage("[Werkzaamheden] WerkzaamMetGevaarlijkeStoffen niet gevuld")
public void valideerWerkzaamMetGevaarlijkeStoffen() throws DomeinValidatieException {
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen(null);
validator.valideer(); //Only this one is tested
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen("bla");
validator.valideer(); //This is NOT tested
}
Run the code through a debugger. My guess is that the first call to valideer() does indeed throw an exception even though you don't expect it.
The JUnit assertXXX methods work by throwing exceptions (specifically AssertionError). So when an exception is thrown (either by your code, or by an assert) control exits from the test method. There isn't any way to restart from the place where the exception is thrown.
You probably want Parameterized, which allows you to run the same tests multiple times with different parameters.
EDIT: I suspect that valideer() is throwing an Exception. To explain a bit further, let's paraphrase your code. When you define a rule, what you're effectively doing is the following:
try {
base.evaluate(); // this calls valideerWerkzaamMetGevaarlijkeStoffen()
Assert.fail("DomeinValidatieException not thrown");
} catch (DomeinValidatieException e) {
// evaluate whether or not the test has failed or not
}
This means that if your first call to valideer() throws an Exception, then control is transferred to the catch block above. There isn't a chance to continue executing the test, because the control has passed elsewhere. You can pass/fail the test as much as you like, but control has passed to the catch block above.
By the way, MethodRule has been deprecated in the later versions, you should be using TestRule instead.
What's the actual use of 'fail' in JUnit test case?
Some cases where I have found it useful:
mark a test that is incomplete, so it fails and warns you until you can finish it
making sure an exception is thrown:
try{
// do stuff...
fail("Exception not thrown");
}catch(Exception e){
assertTrue(e.hasSomeFlag());
}
Note:
Since JUnit4, there is a more elegant way to test that an exception is being thrown:
Use the annotation #Test(expected=IndexOutOfBoundsException.class)
However, this won't work if you also want to inspect the exception, then you still need fail().
Let's say you are writing a test case for a negative flow where the code being tested should raise an exception.
try{
bizMethod(badData);
fail(); // FAIL when no exception is thrown
} catch (BizException e) {
assert(e.errorCode == THE_ERROR_CODE_U_R_LOOKING_FOR)
}
I think the usual use case is to call it when no exception was thrown in a negative test.
Something like the following pseudo-code:
test_addNilThrowsNullPointerException()
{
try {
foo.add(NIL); // we expect a NullPointerException here
fail("No NullPointerException"); // cause the test to fail if we reach this
} catch (NullNullPointerException e) {
// OK got the expected exception
}
}
I've used it in the case where something may have gone awry in my #Before method.
public Object obj;
#Before
public void setUp() {
// Do some set up
obj = new Object();
}
#Test
public void testObjectManipulation() {
if(obj == null) {
fail("obj should not be null");
}
// Do some other valuable testing
}
This is how I use the Fail method.
There are three states that your test case can end up in
Passed : The function under test executed successfully and returned
data as expected
Not Passed : The function under test executed successfully but the
returned data was not as expected
Failed : The function did not execute successfully and this was not
intended (Unlike negative test cases that expect a exception to
occur).
If you are using eclipse there three states are indicated by a Green, Blue and red marker respectively.
I use the fail operation for the the third scenario.
e.g. : public Integer add(integer a, Integer b) { return new Integer(a.intValue() + b.intValue())}
Passed Case : a = new Interger(1), b= new Integer(2) and the function returned 3
Not Passed Case: a = new Interger(1), b= new Integer(2) and the function returned soem value other than 3
Failed Case : a =null , b= null and the function throws a NullPointerException
I, for example, use fail() to indicate tests that are not yet finished (it happens); otherwise, they would show as successful.
This is perhaps due to the fact that I am unaware of some sort of incomplete() functionality, which exists in NUnit.
In concurrent and/or asynchronous settings, you may want to verify that certain methods (e.g. delegates, event listeners, response handlers, you name it) are not called. Mocking frameworks aside, you can call fail() in those methods to fail the tests. Expired timeouts are another natural failure condition in such scenarios.
For example:
final CountDownLatch latch = new CountDownLatch(1);
service.asyncCall(someParameter, new ResponseHandler<SomeType>() {
#Override
public void onSuccess(SomeType result) {
assertNotNull(result);
// Further test assertions on the result
latch.countDown();
}
#Override
public void onError(Exception e) {
fail(exception.getMessage());
latch.countDown();
}
});
if ( !latch.await(5, TimeUnit.SECONDS) ) {
fail("No response after 5s");
}
The most important use case is probably exception checking.
While junit4 includes the expected element for checking if an exception occurred, it seems like it isn't part of the newer junit5. Another advantage of using fail() over the expected is that you can combine it with finally allowing test-case cleanup.
dao.insert(obj);
try {
dao.insert(obj);
fail("No DuplicateKeyException thrown.");
} catch (DuplicateKeyException e) {
assertEquals("Error code doesn't match", 123, e.getErrorCode());
} finally {
//cleanup
dao.delete(obj);
}
As noted in another comment. Having a test to fail until you can finish implementing it sounds reasonable as well.