How to test for Exception in #Async method? - java

How can I assert that a certain exception is thrown inside an #Async method?
Because the following exception is caught by Springs SimpleAsyncUncaughtExceptionHandler.
#Service
public class Service {
#Async
public void run() {
throw new RuntimeException();
}
}
public class Test {
#Test
public void test() {
assertDoesNotThrow(() -> service.run()); //this always passes
}
}

If it is possible for your case, separate testing of asynchronicity and the actual unit of work. E.g. write test that will execute (no 'Async' functionality) Service.run() and assert that no/any/some exceptions are thrown.
In second test (utilizing #Async execution) you could test for the actual unit of work i.e. use your Spring provided bean and test for e.g.:
Awaitility.await().atMost(1000, TimeUnit.MILLISECONDS).untilAsserted(() -> runAnyCodeThatChecksTheResultOfYourServiceRunMethod());
Another method might be to replace the return type of the Service.run() method to java.util.concurrent.Future, Spring will then re-throw the exception. From AsyncExecutionAspectSupport.handleError javadoc:
"If the return type of the method is a {#link Future} object (again, if applicable), the original exception can be propagated by just throwing it at the higher level. However, for all other cases, the exception will not be transmitted back to the client."

import static org.awaitility.Awaitility.await;
Awaitility.await().atMost(5, TimeUnit.SECONDS)
.untilAsserted(() -> assertThrows(RuntimeException.class, () -> service.run()));

Related

Java + Powermockito: How to Replace or Mock Thread.sleep method

Using PowerMockito, I have been trying to replace or mock the Thread.sleep method.
Wherein, the replacing or mocking method will return and Exception.
I have tried the following examples but no luck:
PowerMockito.replace(PowerMockito.method(Thread.class, "sleep", long.class))
.with((object, method, arguments) -> {
throw new Exception(someRandomExceptionMessage);
});
PowerMockito.when(Thread.class, "sleep", anyLong()).thenThrow(new Exception(someRandomExceptionMessage));
PowerMockito.when(Thread.class, "sleep", 1000L).thenThrow(new Exception("An Exception"));
I guess you have an underTest class calling a function that is using Thread.sleep?
You can rather write your test in this way :
if you have a delay variable that returns the execution duration, you can mock the returned value instead of directly mocking Thread.sleep and then test your exception with #Test(expected = Exception.class) or Exception thrownException = assertThrows() depending on wether you are using JUnit 4 or JUnit 5
if you are using JUnit 5, you can simply use assertTimeout(Duration.ofSeconds(10),() -> { underTest.yourMethodCallingThreadSleep())
if using Mockito, the last version can allows you to mock static methods
Take as a suggestion and a simple way to write your test.
This should work. It is important to note the #PrepareForTest needs to refer the method calling Thread.sleep(), not Thread itself.
class ClassCallingSleep {
public static void methodCallingSleep() throws InterruptedException {
System.out.println("TEST 1");
Thread.sleep(100L);
System.out.println("TEST 2");
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassCallingSleep.class})
public class SleepTest {
#Test
public void test() throws Exception {
PowerMockito.mockStatic(Thread.class);
PowerMockito.doThrow(new InterruptedException("HAHA!")).when(Thread.class);
Thread.sleep(Mockito.anyLong());
ClassCallingSleep.methodCallingSleep();
}
}
Output is as follows (that is, TEST 2 above is not reached).
TEST 1
java.lang.InterruptedException: HAHA!

Spring batch run exception throwable method after each tasklet done in afterstep()

public class TaskletConfiguration {
...
#Bean
public Step step() {
return steps.get("step")
.tasklet(tasklet)
.exceptionHandler(logExceptionHandler()) // Handler for logging exception to specific channel
.build();
}
#Bean
public Job job() {
return jobs.get("job")
.start(step())
.build();
}
}
public class ExampleTasklet implements Tasklet, StepExecutionListener {
...
#Override
public RepeatStatus execute(...) throws Exception {
// Do my tasklet
// Throw if it fails, and be handled by logExceptionHandler()
}
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
// Want to throw so that logExceptionHandler() can handle it as throwing in execute().
throwable_function();
}
}
This is my example code using tasklet in spring boot.
My problem is: I want to throw exception from afterstep(), but the interface does not allow it.
Despite this limitation, why I obsessed with afterstep() is that I want to make abstract class to make Tasklet template which can verify each execution in afterstep(). I want verification to run after all execute() is done, which will be overridden by subclass. So I have no choices but using afterstep().
Any idea to run verification method after each execute() with throwable or afterstep() can pass Exception to logExceptionHandler()? I hope to define logExceptionHandler() in TaskletConfiguration class. It will be obese if it is defined in Tasklet class, as I will make abstract class, which will be inherited by many subclasses.
The StepExecutionListener#afterStep is not designed to throw checked exceptions. Here is an excerpt from its Javadoc:
Called after execution of step's processing logic (both successful or failed).
Throwing exception in this method has no effect, it will only be logged.
Moreover, even if you throw a (runtime) exception in afterStep, the exception won't be passed to the exception handler, it will only be logged as mentioned in the Javadoc.
I think it is too late to throw exceptions in StepExecutionListener#afterStep, this method can be used to check the status of the step execution and modify the ExitStatus if needed to drive the rest of the job execution flow.

How can I check if an internal service threw an exception?

I'm trying to write a unit test for a new service. The service returns void and uses other auto-wired services to do some work. I want to test a case where one of the internal services throws an exception which is caught by the top level service under test. How can I verify in the 'then' clause that the internal service threw an exception if it is caught by the service under test?
I would also like to verify that a static method was called to log the result, but I can't see a way to do that with Spock either. These are the only outputs for the service so I would like to verify that they are working.
To address the first part of your question:
Let's assume we have the following structure:
interface ServiceUnderTest {
void foo()
}
interface InternalService {
int bar() throws IllegalArgumentException
}
class ServiceUnderTestImpl implements ServiceUnderTest {
InternalService internalService
ServiceUnderTestImpl(InternalService internalService) {
this.internalService = internalService
}
void foo() {
try {
internalService.bar()
} catch(IllegalArgumentException ex) {
println "Got you"
}
}
}
You're testing method foo() in ServiceUnderTest and it returns void
So I suggest creating Stub of Internal Service that throws exception upon invocation of its bar method
The test will check that no exception has been thrown when calling foo (which means that the exception thrown by internal service was caught and handled correctly)
The test can look like this:
class SampleSpockTest extends Specification {
def "test sample" () {
given:
def internalService = Stub(InternalService)
def subject = new ServiceUnderTestImpl(internalService)
internalService.bar() >> {throw new IllegalArgumentException("Sample
exception")}
when:
subject.foo()
then:
noExceptionThrown()
}
}
I think that you shouldn't check in "then clause that the internal service threw an exception" as you say, actually you're checking the ServiceUnderTest. Its not optimal that it returns void, because you can't really know what did it do, maybe by checking its internal state after the invocation of method foo or something, but at least you can check that the exception was processed if internal service was called and threw and exception.
Regarding the static method mocking, you shouldn't do it probably, mocks do not play well with static calls. You can use "special" tools like PowerMock or PowerMockito, but I believe, they point on a code smell and should be primarily used for legacy code. Its only my opinion, though.

Apache Commons Validator and JUnit

I'm using Apache Commons Validator to validate input within a builder pattern.
Once build() is called on the builder, the variables are checked using methods such as:
Validate.notNull(oranges, "Oranges was not set.");
When testing my code, I can see that when I do not set oranges, I do indeed get the message "Oranges was not set". However, the exception that is thrown is still a NullPointerException.
In my unit tests, I want to check that the validator is used and a message is output, but clearly using:
#Test(expected = NullPointerException.class)
will pass regardless of whether the Validator is used or a message is set.
Is there a way I can check that the validator is used and the message is set in JUnit? If not, is there a library that will allow me to do this?
You should only check the external behaviour of your code. In your case this is: it throws a NullPointerException with the appropriate message.
There are different ways for testing exceptions (see JUnit Wiki). You can always use JUnit's ExpectedException rule
public class YourTest {
#Rule
public final ExpectedException thrown = ExpectedException.none();
#Test
public void test() {
...
thrown.expect(NullPointerException.class);
thrown.expectMessage("Oranges was not set.");
builder.build();
}
}
With Java 8 you can use the method exceptionThrownBy provided by the library Fishbowl. It allows you to use Arrange-Act-Assert pattern.
public class YourTest {
#Test
public void test() {
...
Throwable exception = exceptionThrownBy(() -> builder.build());
assertEquals(NullPointerException.class, exception.getClass());
assertEquals("Oranges was not set.", exception.getMessage());
}
}

Unit testing that log message written when exception caught

Here is the code that I am working with. In this test I want to verify that the log method is being called when an exception is caught.
public class SuperClass(){
public void log()
{
do some logging;
}
}
public class ClassUnderTest extends SuperClass(){
public String methodbeingtested(Object param)
{
try
{
String a = SomeObject.
methodthatthrowsexception(param);//static method, throws JAXB/NPE
}
catch(Exception exp)
{
log("log msg",exp);//inherited method
}
}
}
public class ClassUnderTestTest {
#Test
public testmethodbeingtested(){
ClassUnderTest cut = new ClassUnderTest()
ClassUnderTest cutspy = Mockito.spy(cut);
cutspy.methodbeingtested(param);
Mockito.verify(cutspy).log("log msg", new Exception()); // exp is needed to here.
}
}
After looking at several samples, the above was the closest I could get. This testcase forces an exception. But it fails to verify the log method call as Mockito.verify requires the exact exception (exp) that is caught, which the test case does not have access to.
Is there any other way to test this scenario?
Mockito's verify method can be used with argument matchers. If you want to verify that log was called, with any Exception at all as the second argument, you can just write
verify(cutspy).log(eq("log msg"), any(Exception.class));
I've assumed that you have the right static imports for verify, eq and any.
As an aside, this test does not need PowerMock. Your line PowerMock.expectLastCall().once(); is both redundant and confusing, and should probably be removed, along with the #PrepareForTest annotation.
Instead of spying on ClassUnderTest, you should mock the logging framework, inject it into the class and then verify that the log method gets called. Id' also mock the SomeObject class and have it throw exception.
As an aside, you should really evaluate if you need to verify your log statements. Perhaps you have a valid reason to do so but typically, asserting/verifying to this extent is not required and will only make your tests brittle.

Categories

Resources