I have been converting some code to be asynchronous. The original unit test used the annotation #Test(expected = MyExcpetion.class) but I don't think this will work because the exception I want to assert on is wrapped in java.util.concurrent.ExcutionException . I did try calling my future like this but my assertion is still failing and I don't love that I had to add in return null
myApiCall.get(123).exceptionally((ex) -> {
assertEquals(ex.getCause(),MyCustomException.class)
return null
}
I also tried this flavor but still not working
myApiCall.get(123).exceptionally((ex) -> {
assertThat(ex.getCause())
.isInstanceOF(MyException.class)
.hasMessage("expected message etc")
return null;
}
My API just throws exception if it can't find id. How should I be properly testing this? Can I use that original annotation in anyway?
my api call reaches out to db when run. In this test I am setting up my future to return an error so it doesn't actually try to communicate with anything. the code under test looks like this
public class myApiCall {
public completableFuture get(final String id){
return myService.getFromDB(id)
.thenApply(
//code here looks at result and if happy path then returns it after
//doing some transformation
//otherwise it throws exception
)
}
}
in the unit test I force myService.getFromDB(id) to return bad data so I can test exception and also keep this a unit test don't reach out to db etc.
Let's assume your API throws if called with 0:
public static CompletableFuture<Integer> apiCall(int id) {
return CompletableFuture.supplyAsync(() -> {
if (id == 0) throw new RuntimeException("Please not 0!!");
else return id;
});
}
You can test that it works as expected with the following code (I'm using TestNG but I suspect it won't be too difficult to translate into a JUnit test):
#Test public void test_ok() throws Exception {
CompletableFuture<Integer> result = apiCall(1);
assertEquals(result.get(), (Integer) 1);
}
#Test(expectedExceptions = ExecutionException.class,
expectedExceptionsMessageRegExp = ".*RuntimeException.*Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
result.get();
}
Note that the second test uses the fact that the ExecutionException message will contain the original exception type and message and captures the expectation with a regex. If you can't do that with JUnit, you can call result.get() in a try/catch block and call throw e.getCause(); in the catch block. In other words, something like this:
#Test(expectedExceptions = RuntimeException.class,
expectedExceptionsMessageRegExp = "Please not 0!!")
public void test_ex() throws Throwable {
CompletableFuture<Integer> result = apiCall(0);
try {
result.get();
} catch (ExecutionException e) {
throw e.getCause();
}
}
You can try also alternative option:
import org.hamcrest.core.IsInstanceOf;
import org.junit.rules.ExpectedException;
public class Test() {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void myApiCallTest() {
thrown.expect(ExcutionException.class);
thrown.expectCause(IsInstanceOf.instanceOf(MyException.class));
thrown.expectMessage("the message you expected");
myApiCall.get("");
}
}
Assuming that:
public class myApiCall {
public completableFuture get(final String id) {
// ...
throw new ExcutionException(new MyException("the message you expected"))
}
}
Assume that you have a class and you want to test a method which returns a completable future:
public class A {
private final Api api;
public A(Api api) { this.api = api;}
public CompletableFuture<Void> execute(Integer input) {
final CompletableFuture<Void> future = api.execute(input)
.thenApplyAsync(result -> doSomething())
.exceptionally(ex -> doFailure());
return future;
}
}
To test the execution of "doSomething()" then you may use mockito and do the following:
// prepare test
final Api api = mock(Api.class)
final A a = new A(api);
when(api.execute(any(Integer.class)))
.thenReturn(CompletableFuture.completedFuture(null));
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
...
To test "doFailure" do the following:
when(api.execute(any(Integer.class))).thenAnswer(answer -> {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException());
return future;
});
// execute
final CompletableFuture<Void> result = a.execute(input);
// validate
assertTrue(result.isCompletedExceptionally());
that is easy thing doing in junit-4. Are you remember the #RunWith annotation? Yes, write your own TestRunner to intercept the exception before the junit expected exception processor is invoked, for example:
public class ConcurrentRunner extends BlockJUnit4ClassRunner {
public ConcurrentRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected Statement possiblyExpectingExceptions(FrameworkMethod method,
Object test,
Statement next) {
return super.possiblyExpectingExceptions(
method, test, throwingActualException(next)
);
}
private Statement throwingActualException(Statement next) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
next.evaluate();
} catch (ExecutionException | CompletionException source) {
throw theActualExceptionOf(source);
}
}
private Throwable theActualExceptionOf(Exception source) {
return source.getCause() != null ? source.getCause() : source;
}
};
}
}
just annotated with #RunWith(ConcurrentRunner.class) on the test, you needn't change your test code at all. for example:
#RunWith(ConcurrentRunner.class)
public class ConcurrentExpectedExceptionTest {
#Test(expected = IllegalArgumentException.class)
public void caughtTheActualException() throws Throwable {
myApiCall().join();
}
private CompletableFuture<Object> myApiCall() {
return CompletableFuture.supplyAsync(() -> {
throw new IllegalArgumentException();
});
}
}
Related
I have a class name HibernateSessionManager which have static method
public static HibernateSessionManager current;
I trying to mock
public Mbc_session getMBCSessionByGuid(String sessionGuid) {
try {
return HibernateSessionManager.current.withSession(hibernateSession -> {
return hibernateSession.get(Mbc_session.class, sessionGuid);
});
}
catch (Exception e) {
logger.error().logFormattedMessage(Constants.MBC_SESSION_GET_ERROR_STRING,
e.getMessage()); throw new DAOException(ErrorCode.MBC_1510.getCode(), ErrorCode.MBC_1510.getErrorMessage() + ",Operation: getMBCSessionByGuid");
}
}
i am using following function in #before
public static void initMocks(Session session) {
HibernateSessionManager.current = mock(HibernateSessionManager.class,Mockito.RETURNS_DEEP_STUBS);
HibernateTransactionManager.current = mock(HibernateTransactionManager.class,Mockito.RETURNS_DEEP_STUBS);
doCallRealMethod().when(HibernateTransactionManager.current).withTransaction(any(), any());
doCallRealMethod().when(HibernateSessionManager.current).withSession(any(Consumer.class));
// Mockito.when(HibernateSessionManager.current.withSession((Consumer<Session>) any(Function.class))).thenCallRealMethod();
when(HibernateSessionManager.current.getSession()).thenReturn(session);
}
My test case is following
#Test public void test_getMBCSessionByGuid() {
Mbc_session mbcSession = new Mbc_session();
String sessionGuid = "session GUID";
when(HibernateSessionManager.current.getSession()).thenReturn(session);
// when(sessionFactory.getCurrentSession()).thenReturn(session);
when(session.get(Mbc_session.class, sessionGuid)).thenReturn(mbcSession);
Mbc_session mbcSession2 = mbc_sessionDao.getMBCSessionByGuid(sessionGuid);
assertNull(mbcSession2);
}
it passed but coverage is not touching following code
return hibernateSession.get(Mbc_session.class, sessionGuid);
here is my withSession code
public void withSession(Consumer<Session> task) {
Session hibernateSession = getSession();
try {
task.accept(hibernateSession);
} finally {
HibernateSessionManager.current.closeSession(hibernateSession);
}
}
openSession
public Session getSession() {
Session threadCachedSession = threadSession.get();
if (threadCachedSession != null) {
if (!threadCachedSession.isOpen()) { throw new
IllegalStateException("Session closed outside of
HibernateSessionManager.");
}
return threadCachedSession;
} return sessionFactory.openSession();
}
Looking at the code and assuming it compiles, I believe the problem is that you have two withSession(...) methods and in the code posted you are trying to mock the wrong one. Here are their signatures:
// You should NOT mock this one
void withSession(Consumer<Session> task) {
...
}
// You should mock this one instead
Mbc_session withSession(Function<Session, Mbc_session> task) {
...
}
It was easy to guess as the getMBCSessionByGuid method contains the snippet below with the Function<Session, Mbc_session> being passed as an argument to withSession(...) instead of Consumer<Session>:
return HibernateSessionManager.current.withSession(hibernateSession -> {
// something is returned which means a Function is passed, not a Consumer
return hibernateSession.get(Mbc_session.class, sessionGuid);
});
As an easy fix, you can just add the following to the test:
doCallRealMethod().when(HibernateSessionManager.current).withSession(any(Function.class));
and remove the existing mock configuration with a Consumer:
doCallRealMethod().when(HibernateSessionManager.current).withSession(any(Consumer.class));
P.S. Just in case, I can easily reproduce the issue on my machine.
I am working on Spring Boot 2 to create a microservice. I have a requirement to create an After aspect to execute some piece of code.
#Aspect
#Component
public class FinallyAspect {
#Pointcut("#annotation(finallyEvent)")
public void runFinallyMethod(FinallyEvent finallyEvent) {}
#After("runFinallyMethod(FinallyEvent finallyEvent)")
public void finallyMethod(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
// ...
}
}
Is it possible to get inside finallyMethod whether an exception has occurred or the method returned successfully? I can do it with #AfterReturning and #AfterThrowing annotation, but if there is a way to check if the method has ended in error or success then I can check it in a single function.
It is not possible with After-advice to access whether the method returned successfully or with an exception. There are alternatives...
a) Around-advice (not recommended)
What you want can be manually implemented with a single method using the Around-advice, the most general kind of advice. It is recommended that you use the least powerful advice type that can implement the required behaviour (source). I do not recommend this approach as it can be error-prone in terms of exception handling if implemented the wrong way. For example, if you put your success-code in the try-block, exceptions thrown by this success-code are also caught by the same catch-block as is used for the failure-code. Also, you need to make sure to re-throw the exception and to return the return value of joinPoint.proceed().
This is how could do this properly if you wanted to:
#Around(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public Object finallyMethod(ProceedingJoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
final Object res;
try {
res = joinPoint.proceed();
} catch (Throwable e) {
// code in case of failure
throw e;
}
// code in case of success
return res;
}
b) Clean solution with private method
In this case, I suggest to use AfterReturning-advice and AfterThrowing-advice and then call a private method with a parameter indicating success/error. This is much more readable, does not have the drawbacks of the Around-advice but uses a bit more code.
A boolean (success) is needed
#AfterReturning(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public void finallyMethodReturning(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
finallyMethod(joinPoint, finallyEvent, true);
}
#AfterThrowing(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public void finallyMethodThrowing(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
finallyMethod(joinPoint, finallyEvent, false);
}
private void finallyMethod(JoinPoint joinPoint, FinallyEvent finallyEvent, boolean success) throws Throwable {
if (success) {
// code in case of success
} else {
// code in case of failure
}
}
The Throwable is needed
#AfterReturning(value = "runFinallyMethod(finallyEvent)", argNames = "joinPoint,finallyEvent")
public void finallyMethodReturning(JoinPoint joinPoint, FinallyEvent finallyEvent) throws Throwable {
finallyMethod(joinPoint, finallyEvent, null);
}
#AfterThrowing(value = "runFinallyMethod(finallyEvent)", throwing = "t", argNames = "joinPoint,finallyEvent,t")
public void finallyMethodThrowing(JoinPoint joinPoint, FinallyEvent finallyEvent, Throwable t) throws Throwable {
finallyMethod(joinPoint, finallyEvent, t);
}
private void finallyMethod(JoinPoint joinPoint, FinallyEvent finallyEvent, Throwable t) throws Throwable {
if (t == null) {
// code in case of success
} else {
// code in case of failure
}
}
I don't think you will be able to implement this using #After as this annotation can only give you the JoinPoint in context, which has no information about return values.
If you want to handle everything within the same method I think the only alternative is to implement this using #Around, where you can do something before and after a method execution. Your implementation could be:
#Around("runFinallyMethod(FinallyEvent finallyEvent)")
public Object finallyMethod(ProceedingJoinPoint jp, FinallyEvent finallyEvent) throws Throwable {
try {
Object result = jp.proceed();
// do nice stuff with result
return result;
} catch(Throwable throwable) {
// do nice stuff with the exception;
throw throwable;
}
}
I have a method called doParallelThings:
public Dummy doParallelThings(Map<String, String> mapp) throws Exception {
Dummy dummy = new Dummy();
CompletableFuture<Ans1> one = firstService.getOne(mapp.get("some1"), mapp);
CompletableFuture<Ans2> two = secondService.getTwo(headersMap.get("some2"), mapp);
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(one, two);
try {
combinedFuture.get();
dummy.setOne(one.get());
dummy.setTwp(two.get());
} catch (Throwable e) {
}
return dummy;
}
Code works fine but when I'm trying to test it,
combinedFuture.get(); goes to infinite loop.
Unit test is as below:
#Mock
private CompletableFuture<Void> ans;
#Test
public void testDoParallelThings() throws Exception {
PowerMockito.mockStatic(CompletableFuture.class);
PowerMockito.when(CompletableFuture.allOf(any())).thenReturn(ans);
when(ans.get()).thenReturn(null);
Dummy dummy = dummyService. doParallelThings(mockMap);
assertNotNull(dummy);
}
I have also added #RunWith(PowerMockRunner.class)
#PrepareForTest({CompletableFuture.class}) above the test class.
What am I missing?
when(firstService.getOne(any(), any())).thenReturn(CompletableFuture.completedFuture(mockOne));
solved my problem
I have never really worked with asynchronous programming in Java and got very confused on the practice is the best one.
I got this method
public static CompletableFuture<Boolean> restoreDatabase(){
DBRestorerWorker dbWork = new DBRestorerWorker();
dbWork.run();
return "someresult" ;
}
then this one which calls the first one
#POST
#Path("{backupFile}")
#Consumes("application/json")
public void createOyster(#PathParam("backupFile") String backupFile) {
RestUtil.restoreDatabase("utv_johan", backupFile);
//.then somemethod()
//.then next method()
}
What I want to do is first call the restoreDatabase() method which calls dbWork.run() (which is an void method) and when that method is done I want createOyster to do the next one and so forth until I have done all the steps needed. Someone got a guideline were to start with this. Which practice is best in today's Java?
As you already use CompletableFuture, you may build your async execution pipeline like.
CompletableFuture.supplyAsync(new Supplier<String>() {
#Override
public String get() {
DBRestorerWorker dbWork = new DBRestorerWorker();
dbWork.run();
return "someresult";
};
}).thenComposeAsync((Function<String, CompletionStage<Void>>) s -> {
CompletableFuture<String> future = new CompletableFuture<>();
try{
//createOyster
future.complete("oyster created");
}catch (Exception ex) {
future.completeExceptionally(ex);
}
return null;
});
As you could see, You can call thenComposeAsync or thenCompose to build a chain of CompletionStages and perform tasks using results of the previous step or make Void if you don't have anything to return.
Here's a very good guide
You can use AsyncResponse:
import javax.ws.rs.container.AsyncResponse;
public static CompletableFuture<String> restoreDatabase(){
DBRestorerWorker dbWork = new DBRestorerWorker();
dbWork.run();
return CompletableFuture.completedFuture("someresult");
}
and this
#POST
#Path("{backupFile}")
#Consumes("application/json")
public void createOyster(#PathParam("backupFile") String backupFile,
#Suspended AsyncResponse ar) {
RestUtil.restoreDatabase("utv_johan", backupFile)
.thenCompose(result -> doSomeAsyncCall())
.thenApply(result -> doSomeSyncCall())
.whenComplete(onFinish(ar))
//.then next method()
}
utility function to send response
static <R> BiConsumer<R, Throwable> onFinish(AsyncResponse ar) {
return (R ok, Throwable ex) -> {
if (ex != null) {
// do something with exception
ar.resume(ex);
}
else {
ar.resume(ok);
}
};
}
i have this code in my program which is needed to be tested with jUnit
void deleteCustomer(String name) throws UnknownCustomerException,
AccountNotEmptyException {
if (name == null) {
throw new NullPointerException();
} else if (!exists(name)) {
throw new UnknownCustomerException();
} else if (getCustomer(name).deletable()) {
customerList.remove(getCustomer(name));
}
}
I thought i can test it in one JUnit method like
#Test
public void createCustomer(){
System.out.println("createCustomerTest");
try {
element.createCustomer(null);
//fail("Expected an IndexOutOfBoundsException to be thrown");
} catch (NullPointerException anIndexOutOfBoundsException) {
assertTrue(anIndexOutOfBoundsException.getMessage().equals("NullPointerException"));
}
}
As you can see I already tried unsuccessfully to implement the NPE.
How can I check for several Exceptions in one JUnit Method? I checked some How-To's in the web but failed with that too.
I think in your case you should have separate tests, however you can achieve this like so if using Java 8:
Using an AssertJ 3 assertion, which can be used alongside JUnit:
import static org.assertj.core.api.Assertions.*;
#Test
public void test() {
Element element = new Element();
assertThatThrownBy(() -> element.createCustomer(null))
.isInstanceOf(NullPointerException.class)
.hasMessageContaining("NullPointerException");
assertThatThrownBy(() -> element.get(1))
.isInstanceOf(IndexOutOfBoundsException.class);
}
It's better than #Test(expected=IndexOutOfBoundsException.class) or .expect syntax because it guarantees the expected line in the test threw the exception and lets you check more details about the exception, such as message.
Maven/Gradle instructions here.
Write for each exception its own test. It will be only one thrown at a time anyway.
For example a simplified method:
void deleteCustomer( String name ) throws UnknownCustomerException
{
if ( name == null )
{
throw new NullPointerException();
}
else if ( !exists( name ) )
{
throw new UnknownCustomerException();
}
}
You have then two tests that each check if its exception is thrown:
#Test( expected = NullPointerException.class )
public void deleteCustomer_shouldThrowNullpointerIfNameIsNull() throws UnknownCustomerException
{
String name = null;
cut.deleteCustomer( name );
}
#Test( expected = UnknownCustomerException.class )
public void deleteCustomer_shouldThrowUnknownCustomerExceptionIfNameIsUnknown() throws UnknownCustomerException
{
String name = "someUnknownName";
cut.deleteCustomer( name );
}
The problem with the NullpointerException is, that the test is true/successful/green if the NPE is thrown anywhere in the method - so you should make sure, that that is not happening for the test to be meaningful.
You could add several "catch" statement into the test method for different exceptions, like:
try {
element.createCustomer(null);
Assert.fail("Exception was expected!");
} catch (NullPointerException _ignore) {
} catch (UnknownCustomerException _ignore) {
}
or with Java 87
try {
element.createCustomer(null);
Assert.fail("Exception was expected!");
} catch (NullPointerException | UnknownCustomerException _ignore) {
}
But if you switch from JUnit to TestNG, then your test will be much cleaner:
#org.testng.annotations.Test(expectedExceptions = { NullPointerException.class, UnknownCustomerException.class })
public void createCustomer() throws NullPointerException, UnknownCustomerException {
element.createCustomer(null);
}
More information about "expectedException" is here: http://testng.org/doc/documentation-main.html and example of the usage can be found here: http://www.mkyong.com/unittest/testng-tutorial-2-expected-exception-test/
I suggest that you take a closer look at the JavaDoc of ExpectedException and implement different tests for different validations, e.g.
public class CustomerTest {
#Rule
public ExpectedException exception = ExpectedException.none();
#Test
public void throwsNullPointerExceptionForNullArg() {
exception.expect(NullPointerException.class);
element.createCustomer(null);
}
#Test
public void throwsUnknwonCustomerExceptionForUnkownCustomer() {
exception.expect(UnknownCustomerException.class);
// exception.expectMessage("Some exception message"); uncomment to verify exception message
element.createCustomer("unknownCustomerName");
}
#Test
public void doesNotThrowExceptionForKnownCustomer() {
element.createCustomer("a known customer");
// this test pass since ExpectedException.none() defaults to no exception
}
}