How to test #Async Spring methods with junit? - java

I have an #Async method and want to test it with junit.
Problem: I want junit to fire all calls to the async method without blocking, so don't want for the outcome.
But in my following example, each call first waits for the async method to return, and then continue with the next incovation:
#Service
public class MainService {
#Autowired
private SubService sub;
#Async
public void processAsync() {
sub.run();
}
}
#SpringBootTest
public class MainServiceTest {
#Autowired
private MainService service;
#MockBean
private SubService sub;
#Test
public void testAsync() {
final CountDownLatch latch = new CountDownLatch(5);
when(sub.run()).then((answer) -> {
latch.countDown();
latch.await(); //return when latch is 0
return;
}
for (int i = 0; i<6; i++) {
//TODO this currently runs in sync. why?
service.processAsync();
}
}
}
I want all service calls to block until latch count reaches 0, and then continue the test.
But what I get is that the SubService is only called once, and then stucks inside the mocked Answer method.
Question: why are my service.process() calls inside the #Test method not fired 5x directly?

The follow clue is to let sub-method wait for a CountDownLatch. This way, all threads will first be started and wait inside the subroutine.
Then, inside the test method, release the latch, so that all methods continue:
#Test
public void testAsync() {
CountDownLatch waiter = new CountDownLatch(1);
when(sub.run()).then((answer) -> {
waiter.await();
return;
}
Stream.generate(() -> new Thread(() -> service.processAsync()))
.limit(6)
.forEach(Thread::start);
waiter.countDown(); //resumes all waiting threads
}

Related

Singleton and Multithread in SpringBoot. Is it really multi thread?

Since I am not working specifically on multi threads, the questions can be low level or even silly, please excuse me =)
Here is my code call flow like;
MessageNotificationJobExecutionConfig -> AsyncMessageNotificationJobExecutor -> NotificationJobExecutor.execute()
MessageNotificationJobExecutionConfig (finds the objects to process) and calls AsyncMessageNotificationJobExecutor inside the loop
AsyncMessageNotificationJobExecutor has #Async("messageNotificationTaskExecutor") annotation over the execute() method.
AsyncMessageNotificationJobExecutor.execute() method calls NotificationJobExecutor.execute()
messageNotificationTaskExecutor is an instance of ThreadPoolTaskExecutor
Here is my question;
If am not wrong as default NotificationJobExecutor has a singletone instance.
Even if AsyncMessageNotificationJobExecutor work async and use thread pool task executor, all thread call only NotificationJobExecutor instance (singletone).
I am not sure, I may misunderstand that Thread_1 calls NotificationJobExecutor.execute() and until this thread finish its job other thread wait for Thread_1. Is my inference correct ?
I think even if it looks multi thread actually it works singletone
#Component("messageNotificationTaskExecutor")
public class MessageNotificationThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
#Value("${message.notification.task.executor.corePoolSize}")
Integer corePoolSize;
#Value("${message.notification.task.executor.maxPoolSize}")
Integer maxPoolSize;
#Value("${message.notification.task.executor.queueCapacity}")
Integer queueCapacity;
public MessageNotificationThreadPoolTaskExecutor() {
super();
}
#PostConstruct
public void init() {
super.setCorePoolSize(corePoolSize);
super.setMaxPoolSize(maxPoolSize);
super.setQueueCapacity(queueCapacity);
}
}
#Configuration
public class MessageNotificationJobExecutionConfig {
protected Logger log = LoggerFactory.getLogger(getClass());
#Autowired
AsyncMessageNotificationJobExecutor asyncMessageNotificationJobExecutor;
#Autowired
MessageNotificationThreadPoolTaskExecutor threadPoolTaskExecutor;
#Autowired
JobExecutionRouter jobExecutionRouter;
#Autowired
NotificationJobService notificationJobService;
private Integer operationType = OperationType.ACCOUNT_NOTIFICATION.getValue();
#Scheduled(cron = "${message.notification.scheduler.cronexpression}")
public void executePendingJobs() {
List<NotificationJob> nextNotificationJobList = notificationJobService.findNextJobForExecution(operationType, 10);
for (NotificationJob nextNotificationJob : nextNotificationJobList) {
if (threadPoolTaskExecutor.getActiveCount() < threadPoolTaskExecutor.getMaxPoolSize()) {
asyncMessageNotificationJobExecutor.execute(nextNotificationJob);
}
}
}
}
#Service
public class AsyncMessageNotificationJobExecutor {
#Autowired
NotificationJobExecutor notificationJobExecutor;
#Autowired
NotificationJobService notificationJobService;
#Async("messageNotificationTaskExecutor")
public void execute(NotificationJob notificationJob) {
notificationJobExecutor.execute(notificationJob);
}
}
#Component
public class NotificationJobExecutor implements JobExecutor {
#Override
public Integer getOperationType() {
return OperationType.ACCOUNT_NOTIFICATION.getValue();
}
#Override
public String getOperationTypeAsString() {
return OperationType.ACCOUNT_NOTIFICATION.name();
}
#Override
public void execute(NotificationJob notificationJob) {
// TODO: 20.08.2020 will be execute
}
}
In the scenario you created you have all singleton instances. But the flow looks something like this:
call to executePendingJobs in MessageNotificationJobExecutionConfig
iterate over each NotificationJob sequentially (so this is waiting)
call to execute in AsyncMessageNotificationJobExecutor which will add a execution to the messageNotificationTaskExecutor sequential (thus blocking) to the thread pool
execute the job created in step 3 in a separate thread (so this actually executes your method in AsyncMessageNotificationJobExecutor
a blocking call to the execute method in NotificationJobExecutor
The 'magic' happens in step 3, where rather then executing the method Spring will add a job to the messageNotificationTaskExecutor which wraps the call to step 4. This causes the call for step 4 to happen asynchronous and thus multiple calls to the same instance can occur at the same time. So make sure this object is stateless.

How to run two code segments concurrently: one returns a String the other returns void

My frontend is timing out (504 error) when calling my backend service. This is because my backend service takes ~6 minutes to finish running. I want to return a response to the front-end within a minute and have my backend code continue running after the response is given to the frontend.
I want to use concurrency to run two code segments. One thread will return a String to the frontend, the other thread will call the code that takes around 5 minutes to run on my server.
I want my solution to be simple as this seems like a simple problem to fix, so I am using the simple Executor class from java.util.concurrent
I made my Invoker class as followed:
public class Invoker implements Executor {
#Override
public void execute(Runnable r) {
r.run();
}
}
In my actual code, I have
import java.util.concurrent.Executor;
import com.dcc.standalone.Invoker;
public String aCoolFunction() {
String status = "good job, homie";
Executor executor = new Invoker();
executor.execute( () -> {
// Call this part of the code that takes 5 minutes to run CODE_A
});
return status;
}
I expect status to be returned at the same time CODE_A starts running. Instead, the code runs sequentially as before, i.e., status is returned after CODE_A runs.
maybe use a CompletableFuture?
Setup a ThreadPoolTaskExecutor.
#Configuration
#EnableAsync
public class SpringAsyncConfig {
#Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
Define your function
public String aCoolFunction() {
String status = "good job, homie";
someAsyncFunction();
return status;
}
Define a async long running function.
#Async
public void someAsyncFcuntion() {
// Call this part of the code that takes 5 minutes to run CODE_A
}
run your cool function somewhere in a CompletableFuture
String result CompletableFuture.supplyAsync(() -> aCoolFunction()).get();
I'm writing from mobile, but this is what i could come up with from the top of my head.
Declare #Async or create a threadpool using Executors for the service field you want to use. ex)
#Service
public class SimpleService {
private ExectorService pool = Executors.newFixedThreadPool(10);
public String someThing() {
String status = "good job, homie";
pool.execute(() -> {
// other logic
})
return status;
}
}

In a JUnit test, is there a way I can ensure that all assertions have been executed?

I have a Producer and a Consumer. Producer writes messages synchronously. The consumer is a thread that polls for messages every second.
I have a test like this:
#Test
public void shouldConsumeMessageWhenMessageIsProduced() {
final Message expectedMessage = new Message("test");
//consumer will poll every 1 second for a message
consumer.poll((actualMessage) -> {assertThat(actualMessage), is(expectedMessage));
producer.sendSynchronously(expectedMessage);
Thread.sleep(3000);
}
This test works. However, there is no way for me to ensure that the assertion was actually invoked.
I realize that I could use Mockito, but I also realize that this is more of an integration test than a unit test. But is there anyway in JUnit to ensure that all the assertions have been executed?
Please note since the assertion is in a lambda, I cannot increment a variable or set a flag.
I would make use either AtomicBoolean or MutableBoolean from your lambda expression depending on your preference. See the following code for an example:
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang.mutable.MutableBoolean;
import org.junit.Test;
public class AssertionLambdaTest {
#Test
public void assertExecutedWithAtomicBoolean() {
AtomicBoolean myBoolean = new AtomicBoolean(false);
doStuff(() -> {
assertTrue(true);
myBoolean.set(true);
});
assertTrue(myBoolean.get());
}
#Test
public void assertExecutedWithMutableBoolean() {
MutableBoolean myBoolean = new MutableBoolean(false);
doStuff(() -> {
assertTrue(true);
myBoolean.setValue(true);
});
assertTrue(myBoolean.booleanValue());
}
private void doStuff(Runnable runner) {
runner.run();
}
}
Edit: I just realized that your question said "all assertions". As such, you could equivalently use Apache's MutableInt class or Java's AtomicInteger in the same way, just incrementing until the correct number has been reached.
It seems that you want your test to wait until the assertion is triggered, probably with a time out. A CountDownLatch could do the job:
#Test
public void shouldConsumeMessageWhenMessageIsProduced() {
final Message expectedMessage = new Message("test");
CountDownLatch messageReceived = new CountDownLatch(1);
//consumer will poll every 1 second for a message
consumer.poll(actualMessage -> {
assertThat(actualMessage, is(expectedMessage));
messageReceived.countDown();
}
producer.sendSynchronously(expectedMessage);
//wait until the message is received, but not more than one second
//await returns false if it reaches the timeout
assertTrue(messageReceived.await(1, SECONDS));
}
If you expect the assertion in the consumer to be triggered n times, you can change the initial count of the latch: CountDownLatch latch = new CountDownLatch(n);.

How do I unit test asynchronous methods nicely?

I'm currently unit testing my asynchronous methods using thread locking, usually I inject a CountDownLatch into my asynchronous component and let the main thread wait for it to reach 0. However, this approach just looks plain ugly, and it doesn't scale well, consider what happens when I write 100+ tests for a component and they all sequentially have to wait for a worker thread to do some fake asynchronous job.
So is there another approach? Consider the following example for a simple search mechanism:
Searcher.java
public class Searcher {
private SearcherListener listener;
public void search(String input) {
// Dispatch request to queue and notify listener when finished
}
}
SearcherListener.java
public interface SearcherListener {
public void searchFinished(String[] results);
}
How would you unit test the search method without using multiple threads and blocking one to wait for another? I've drawn inspiration from How to use Junit to test asynchronous processes but the top answer provides no concrete solution to how this would work.
Another approach:
Just dont start the thread. thats all.
Asume you have a SearcherService which uses your Searcher class.
Then don't start the async SearcherService, instead just call searcher.search(), which blocks until search is finished.
Searcher s = new Searcher();
s.search(); // blocks and returns when finished
// now somehow check the result
Writing unit test for async never looks nice.
It's necessary that the testMyAsyncMethod() (main thread) blocks until you are ready to check the correct behaviour. This is necessary because the test case terminates at the end of the method. So there is no way around, the question is only how you block.
A straightforward approach that does not influence much the productive code is to
use a while loop: asume AsyncManager is the class under test:
ArrayList resultTarget = new ArrayList();
AsyncManager fixture = new AsyncManager(resultTarget);
fixture.startWork();
// now wait for result, and avoid endless waiting
int numIter = 10;
// correct testcase expects two events in resultTarget
int expected = 2;
while (numIter > 0 && resulTarget.size() < expected) {
Thread.sleep(100);
numIter--;
}
assertEquals(expected, resulTarget.size());
productive code would use apropriate target in the constructor of AsyncManager or uses another constructor. For test purpose we can pass our test target.
You will write this only for inherent async tasks like your own message queue.
for other code, only unitest the core part of the class that performs the calculation task, (a special algorithm, etc) you dont need to let it run in a thread.
However for your search listener the shown principle with loop and wait is appropriate.
public class SearchTest extends UnitTest implements SearchListener {
public void searchFinished() {
this.isSearchFinished = true;
}
public void testSearch1() {
// Todo setup your search listener, and register this class to receive
Searcher searcher = new Searcher();
searcher.setListener(this);
// Todo setup thread
searcherThread.search();
asserTrue(checkSearchResult("myExpectedResult1"));
}
private boolean checkSearchResult(String expected) {
boolean isOk = false;
int numIter = 10;
while (numIter > 0 && !this.isSearchFinished) {
Thread.sleep(100);
numIter--;
}
// todo somehow check that search was correct
isOk = .....
return isOk;
}
}
Create a synchronous version of the class that listens for its own results and uses an internal latch that search() waits on and searchFinished() clears. Like this:
public static class SynchronousSearcher implements SearcherListener {
private CountDownLatch latch = new CountDownLatch(1);
private String[] results;
private class WaitingSearcher extends Searcher {
#Override
public void search(String input) {
super.search(input);
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public String[] search(String input) {
WaitingSearcher searcher = new WaitingSearcher();
searcher.listener = this;
searcher.search(input);
return results;
}
#Override
public void searchFinished(String[] results) {
this.results = results;
latch.countDown();
}
}
Then to use it, simply:
String[] results = new SynchronousSearcher().search("foo");
There are no threads, no wait loops and the method returns in the minimal possible time. It also doesn't matter if the search returns instantly - before the call to await() - because await() will immediately return if the latch is already at zero.

ScheduledExecutorService doesn't works during my junit test

I am working on writing some junit test for my spring application. Below is my junit test that that calls afterPropertiesSet method of my InitializeFramework class that implements InitializingBean interface.
Below is the flow where my junit test calls afterPropertiesSet method and then that method will call initializeModel method within the same class, and then that method has a scheduler which will call getBundlesInfo method every few minutes. But somehow during my junit, getBundlesInfo method is not getting called at all.
#Test
public void testFramework() {
try {
InitializeFramework io = new InitializeFramework();
io.afterPropertiesSet();
} catch (Exception e) {
}
}
public class InitializeFramework implements InitializingBean {
private static long checkWithDBInterval = 1L;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
#Override
public void afterPropertiesSet() throws Exception {
try {
// other code here
initializeModel();
} catch (Exception e) {
}
}
private void initializeModel() {
final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
new Runnable() {
public void run() {
try {
getBundlesInfo();
} catch(Exception ex) {
// log exception here
}
}
}, 0, checkWithDBInterval, TimeUnit.MINUTES);
}
// this method is not getting called from my junit test
protected static void getBundlesInfo() {
// some code here
// have put the breakpoint here..
}
}
Can anybody help me with this? What wrong I am doing here? but during my application run, this flow works perfectly fine and getBundlesInfo gets called... Only during junit it is not working..
This happens because your unit test exits before the scheduler executes your Runnable.
Do you want to test that afterPropertiesSet calls getBundlesInfo or do you want to test the repeated invocation of getBundlesInfo?
How does your unit test assert that getBundlesInfo got called? Or are you not there yet?
If you just want to see that getBundlesInfo is called, you either could make a direct call to it and increase the initialDelay of your scheduler to checkWithDBInterval, or stub getBundlesInfo with Mockito and/or Powermock to for example use a CountDownLatch to synchronize on.
Well or just wait a couple of seconds after the call to afterPropertiesSet and then check if getBundlesInfo was called (which you can do with Mockito also btw).
In any case, you might want to add code which calls shutdown on the executor service after the test is finished
Since you use Spring:
Consider using the provided Task Execution and Scheduling framework to schedule the repeated call to getBundlesInfo and having afterPropertiesSet directly call getBundlesInfo initially.
Anyway, here is an example with stubbing and using a CountDownLatch for the waiting part.
I also had to make getBundlesInfo non-static, as i couldnt quickly remember/find how to stub a static method.
import static org.mockito.Mockito.*;
import java.util.concurrent.*;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class StackOverflowTest
{
public static class ClassWithScheduler
{
private static long checkWithDBInterval = 1L;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 1 );
public void entryPoint()
{
scheduler.scheduleAtFixedRate( new Runnable() {
public void run()
{
try
{
thisHasToBeCalled();
}
catch( Exception ex )
{
// log exception here
}
}
}, 0, checkWithDBInterval, TimeUnit.MINUTES );
}
protected void thisHasToBeCalled()
{
System.out.println( "thisHasToBeCalled was called" );
}
}
// since we are waiting on another thread either use a timed-wait (latch.await also
// has a variant which accepts a timeout) or use the timeout attribute of the
// #Test annotation
#Test( timeout = 5000L )
public void testCall() throws Exception
{
// create latch which this thread waits on and the scheduler thread
// notifies on
final CountDownLatch latch = new CountDownLatch( 1 );
// create instance
ClassWithScheduler instance = spy( new ClassWithScheduler() );
// stub thisHasToBeCalled to notify on the latch
doAnswer( new Answer<Void>() {
#Override
public Void answer( InvocationOnMock invocation ) throws Throwable
{
// call the real method
invocation.callRealMethod();
// notify waiting thread
latch.countDown();
System.out.println( "stub" );
return null;
}
} ).when( instance ).thisHasToBeCalled();
// execute
instance.entryPoint();
// wait for thread to call the stubbed method
latch.await();
// assert that the method was called /
verify( instance ).thisHasToBeCalled();
}
}
You will notice that if you change your getBundlesInfo() to something like
protected static void getBundlesInfo() {
System.out.println("ay");
}
and the TimeUnit you are using to TimeUnit.MILLISECONDS, that it will print as much as it can. For example, I got
ay
ay
ay
ay
This is because JUnit cleans up any threads running on the JVM before exiting. It kills/stops/interrupts them.

Categories