best approach for junit thread method execution - java

I have more then 100 android based junit test case when I’m executing in jenkin pipeline few are getting failed but individual testcase are working fine in locally.
This Fail is due to junit thread method execution.
In order to solve the issues I have added below approach for each method
Initialize a CountDownLatch with CountDownLatch latch = new CountDownLatch(1).
Pass each runnable a reference to the latch. At the end of the run() method, call latch.countDown().
At the end of the each method call latch.await(). This will block until latch.countDown() has been called
My test case looks like: as shown below
#Test
public void test_MyTest() {
CountDownLatch latch = new CountDownLatch(1);
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
..
..
..
latch.countDown();
}
});
try {
latch.await(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
My Question is:
It’s very painful to apply this latch concept to each and every method , Is there any way we can initialise single time and that should applicable for each test method.
Is this approach is good ? Is there any other recommended solution for this.
Thanks in advance!

Related

How to stop a long running function

Consider this code:
class Solver {
private boolean abort = false;
public void solve(List<Case> cases) {
while(!abort) {
for(Case c : cases)
compute(c); // method that take too long to finish
}
}
// a bunch of methods
public void abort() {
abort = true;
}
}
// in another class
Solver solver = new Solver();
solver.solve(cases);
public void onSolveAborted() {
solver.abort();
}
How can I change this solution so I can abort the solve function instantly. I know I can implements the Runnable interface in Solver class so I can stop the thread. This will introduce many changes in our code and I don't know if the framework we are using allow creating threads.
This will not be possible without the use of threads. Something has to set abort() before the running thread will stop. Take a look at this example:
class Solver implements Runnable {
private List<Case> cases;
public Solver(List<Case> cases) {
this.cases = cases;
}
private void compute(Case c) {
try {
// Do some computation here
} finally {
// Sound the horns! Abandon ship!
}
}
public void solve(List<Object> cases) {
for (Case c : cases) {
try {
compute(c); // method that take too long to finish
} catch (InterruptedException e) {
// Hmm, maybe I should take the hint...
break;
}
}
}
public void run() {
solve(cases);
}
public static void main(String args[]) {
List<Case> cases = new ArrayList<Case>();
// Populate cases
Thread t = new Thread(new Solver(cases));
t.run();
do {
// Wait 30 seconds
t.join(30 * 1000);
// Not done yet? Lets drop a hint..
if(t.isAlive()) {
t.interrupt();
}
} while (t.isAlive());
}
}
Very simply, it launches solve in a thread. The main thread waits up to 30 seconds then interrupts solve method. The solve method catches the interruption and gracefully exits the computation. Unlike your solution using boolean abort, this launches an InterruptedException from anywhere in your thead code (and you should deal with the exception accordingly!) allowing you to halt execution at any time.
If you want more control, you can add the try.. catch inside compute so you can have a finally clause to close any opened files or whatnot. Perhaps better still, have a try.. finally in compute to deal with closing things in a "nice" way and the try.. catch (InterruptedException) in the solve method to handle what happens in the case of interruption (in short, cleanup logic and interruption logic don't have to be in the same method).
Do somthing like this
Let say, you have 100 cases, 10 has been solved and you want to abort remaing 90.
In your code, you are solving all the cases in one iteration, after that while loop check for abort.
public void solve(List<Case> cases) {
Iterator<Case> iterator = cases.iterator();
while (iterator.hasNext() && !abort) {
Case c=iterator.iterator.next();
compute(c);
}
}
Change your class to Runnable and use ExecutorService to run it. Then you can just use methods "shutDown()" or "shutDownNow()" methods. This is cleaner and less intrusive then what you suggested in your own question. Plus killing thread manually is a REALLY BAD idea. At some point in JDK itself in thread method "kill()" was killed as there is no clean way to do so properly

How to test a method using sleep() with Java?

I have the following method and I am struggling to get 100% code coverage.
public final class SleepingHelper {
public static void sleepInMillis(Duration timeOfNextTry) {
try {
Thread.sleep(timeOfNextTry.toMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The question is how can I force Thread.sleep to throw an exception?
Edit: since it was marked as duplicate, I am still wondering what I would assert in the test ? The other question Is more generic.
You need to interrupt it from another thread. For example:
Thread t = new Thread() {
public void run () {
SleeperMillis.sleepInMillis(new Duration(10000000l));
}
}.start();
Thread.sleep(100); // let the other thread start
t.interrupt;
You don't need to actually interrupt the thread. You can use PowerMockito to mock the static method Thread.sleep()
#RunWith(PowerMockRunner.class)
#PrepareForTest(Thread.class)
public class TestClass {
#Test
public void testSleepInMillis() throws Exception {
PowerMockito.mockStatic(Thread.class);
PowerMockito.doThrow(new InterruptedException ()).when(Thread.class);
try {
SleepHelper.sleepInMillis(11);
fail("expected exception");
} catch (InterruptedException e) {
System.out.println("all good");
}
}
You don't test it, because you can't assert its results, and you can't assert it because Thread.sleep is not accurate or guaranteed to sleep for this duration of time, and the test results will differ from run to run.
Mocking is a better option here.
Btw, it is not just that your tests aren't predictable, your code that uses Thread.sleep in production is going to be unpredictable for the same reasons. Thread.sleep(some magic number goes here) usually indicates a badly written program.
I wouldn't bother testing it. 100% coverage is excessive. However, you could do it like this:
#Test
public void testException() throws Exception {
// Capture the system error stream, so that we can test that the expected exception is printed.
ByteArrayOutputStream capturedErrors = new ByteArrayOutputStream();
System.setErr(new PrintStream(capturedErrors));
// Create a new thread on which to run the candidate method.
Thread thread = new Thread() {
#Override
public void run() {
SleepingHelper.sleepInMillis(Duration.ofMillis(10));
}
};
// Start the second thread.
thread.start();
// Interrupt the second thread. (The candidate method hasn't finished yet. It takes 10 milliseconds to run.)
thread.interrupt();
// Wait for the thread to die (and write out the stack-trace).
thread.join();
// Test that the expected exception's stack trace was printed to the system error stream.
// The output should start with the exception's name.
String output = capturedErrors.toString();
int lengthOfExceptionName = "java.lang.InterruptedException".length();
assertEquals(output.substring(0, lengthOfExceptionName), "java.lang.InterruptedException");
}

How can I replace Thread.sleep() in an infinite loop?

I have an infinite loop inside my main, it runs a job which is also an infinite loop, and wait for it to throw an error. Then it sleeps for a given amount of time and starts the task again.
public static void main(String[] args) {
while (true) {
try {
MyClass myClass = new MyClass();
myClass.startInfiniteLoop();
}
catch (SomeException ex) {
try {
Thread.sleep(MyClass.DEFAULT_SLEEP_TIME);
}
catch (InterruptedException ex2) {
System.exit(-1);
}
}
}
}
This works fine, but I wonder if this could be done better, perhaps with an ExecutorService as I (and my IDE) don't like Thread.sleep() in a while (true) loop.
I have read a lot of questions and their answers about ScheduledExecutorService and task management, but I did not find this particular case since it's not really a schedule, I don't know if and when the task if going to end.
You can use a ScheduledExecutorService:
ScheduledExecutorService s=Executors.newScheduledThreadPool(1);
s.scheduleWithFixedDelay(new Runnable() {
public void run() {
try {
MyClass myClass = new MyClass();
myClass.startInfiniteLoop();
} catch(SomeException ex) {}
}
}, 0, MyClass.DEFAULT_SLEEP_TIME, TimeUnit.MILLISECONDS);
The key point is to use scheduleWithFixedDelay rather than scheduleAtFixedRate to ensure the specified time elapses between the subsequent executions just like with your sleep approach. However, note that even with “fixed rate” the new execution will not start when the old one has not finished yet. It’s documentation says: “If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.”
Further note that you still have to catch the exception like in my code example as otherwise the executor will cancel the scheduled task once it threw an uncatched exception.
If you can take the MyClass and rework it to have a Runnable that does what only one loop iteration of the MyClass would have done, then you can use a scheduling executor service, telling the service to run the Runnable once every time period.
--- Updated by request of a quick example ---
The following is not strictly correct Java code, it is pesudo-java.
public class MyRepeatingTask implements Runnable {
private final ScheduledThreadpoolExecutor executor;
public MyRepeatingTask(ScheduledThreadpoolExecutor executor) {
this.executor = executor;
}
public void run() {
try {
doMyVariableLengthThing();
// alternatively, you could also schedule a new instance
executor.schedule(this, 1, TimeUnit.SECONDS);
} catch (Exception e) {
cleanup();
}
}
}
and then to start the ball rolling
ScheduledThreadpoolExecutor executor = new ScheduledThreadpoolExecutor(1);
executor.execute(new MyRepeatingTask(executor));

Weird problem using JUnit in multi-thread environment

I meet a weired problem when using JUnit in multi-thread environment. The following code should fail, but it actually pass in eclipse.
public class ExampleTest extends TestCase {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private volatile boolean isDone = false;
public void test() throws InterruptedException, ExecutionException {
executor.submit(new Runnable() {
#Override
public void run() {
try {
fail();
} finally {
isDone = true;
}
}
});
while (!isDone) {
Thread.sleep(1000);
}
}
}
And here'a another piece of code, here I use Future.get() to wait for thread stop, in this case it will fail.
public class ExampleTest extends TestCase {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private volatile boolean isDone = false;
public void test() throws InterruptedException, ExecutionException {
Future future=executor.submit(new Runnable() {
#Override
public void run() {
try {
fail();
} finally {
isDone = true;
}
}
});
future.get();
}
}
I googled it and found that JUnit can not handle Multiple-thread unit testing,but what's the differences between these two pieces of code ? Thanks
JUnit cannot see the exceptions that occur in threads other than the thread in which the tests are running. In the first case, through an exception occurs by calling fail, it occurs in a separate thread run by the executor. Hence it is not visible to JUnit and the test passes.
In the second case, the same exception happens in the separate thread run by the executor but the exception is effectively "reported back" to the test thread when you call future.get. This is because future.get throws an ExecutionException if the computation of the future failed due to any exception. JUnit is able to see this exception and hence the test fails.
As #abhin4v has pointed out, the exception in the new thread gets swallowed. You could try providing your own fail-method that syncronises with the top-level thread very much like in your example with get().
But there's no need to use Futures, just write to a shared variable indicating failure and use newThreadId.join(). Apart from that, I'm not aware of any other way of solving this in plain JUnit.
Take a look at http://www.youtube.com/watch?v=wDN_EYUvUq0 (starting at 17:09), it explain problems you can get with JUnit and threads.
I think, that in your case, get() throws a ExecutionException and that's why the second test fails. In the first testcase, jUnit doesn't see the exception.
There is also the interesting fact that Eclipse and IDEA can spawn a VM in their junit test runners and end up calling system.exit() on it. This means if you don't wait properly in the test (as in the case when you sleep above and hope the the task has completed), it can exit unexpectedly. Interesting, but not exactly what you were asking!
see this link for details...

How to write unit test for "InterruptedException"

In attempts of 100% code coverage, I came across a situation where I need to unit test block of code that catches an InterruptedException. How does one correctly unit test this? (JUnit 4 syntax please)
private final LinkedBlockingQueue<ExampleMessage> m_Queue;
public void addMessage(ExampleMessage hm) {
if( hm!=null){
try {
m_Queue.put(hm);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Right before invoking addMessage(), call Thread.currentThread().interrupt(). This will set the "interrupt" status flag on the thread.
If the interrupted status is set when the call to put() is made on a LinkedBlockingQueue, an InterruptedException will be raised, even if no waiting is required for the put (the lock is un-contended).
By the way, some efforts to reach 100% coverage are counter-productive and can actually degrade the quality of code.
Use a mocking library like Easymock and inject a mock LinkedBlockingQueue
i.e.
#Test(expected=InterruptedException.class)
public void testInterruptedException() {
LinkedBlockingQueue queue = EasyMock.createMock(LinkedBlockingQueue.class);
ExampleMessage message = new ExampleMessage();
queue.put(message);
EasyMock.expectLastCall.andThrow(new InterruptedException());
replay(queue);
someObject.setQueue(queue);
someObject.addMessage(msg);
}
As stated above just make use Thread.currentThread().interrupt() if you caught InterruptedException and isn't going to rethrow it.
As for the unit testing. Test this way: Assertions.assertThat(Thread.interrupted()).isTrue();. It both checks that the thread was interrupted and clears the interruption flag so that it won't break other test, code coverage or anything below.
Another option is to delegate dealing with InterruptedException to Guava's Uninterruptibles, so you don't need to write and test your custom code for it:
import static com.google.common.util.concurrent.Uninterruptibles.putUninterruptibly;
private final LinkedBlockingQueue<ExampleMessage> queue;
public void addMessage(ExampleMessage message) {
putUninterruptibly(queue, message);
}
One proper way could be customizing/injecting the ThreadFactory for the executorservice and from within the thread factory, you got the handle of the thread created, then you can schedule some task to interrupt the thread being interested.
Demo code part for the overwrited method "newThread" in ThreadFactory:
ThreadFactory customThreadfactory new ThreadFactory() {
public Thread newThread(Runnable runnable) {
final Thread thread = new Thread(runnable);
if (namePrefix != null) {
thread.setName(namePrefix + "-" + count.getAndIncrement());
}
if (daemon != null) {
thread.setDaemon(daemon);
}
if (priority != null) {
thread.setPriority(priority);
}
scheduledExecutorService.schedule(new Callable<String>() {
public String call() throws Exception {
System.out.println("Executed!");
thread.interrupt();
return "Called!";
}
},
5,
TimeUnit.SECONDS);
return thread;
}
}
Then you can use below to construct your executorservice instance:
ExecutorService executorService = Executors.newFixedThreadPool(3,
customThreadfactory);
Then after 5 seconds, an interrupt signal will be sent to the threads in a way each thread will be interrupted once in executorservice.
The example code in the question may be testable by calling Thread.currentThread().interrupt(). However, besides the mentioned problems various methods reset the interrupted flag. An extensive list is for example here: https://stackoverflow.com/a/12339487/2952093. There may be other methods as well.
Assuming waiting implemented as follows should be tested:
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException ex) {
// Set the interrupt flag, this is best practice for library code
Thread.currentThread().interrupt();
throw new RuntimeException(ex);
}
A call to Thread.sleep itself clears the interrupted flag, so it cannot be set in advance. It can be tested using its own test thread as follows:
AtomicBoolean threadInterrupted = new AtomicBoolean(false);
Runnable toBeInterrupted = () -> {
try {
methodUnderTest();
} catch (RuntimeException unused) {
// Expected exception
threadInterrupted.set(true);
}
};
// Execute the in an operation test thread
Thread testThread = new Thread(toBeInterrupted);
testThread.start();
// When the test thread is waiting, interrupt
while (!threadInterrupted.get()) {
if (testThread.getState() == Thread.State.TIMED_WAITING) {
testThread.interrupt();
}
}
// Assert that the interrupted state is re-set after catching the exception
// Must be happening before thread is joined, as this will clear the flag
assertThat(testThread.isInterrupted(), is(true));
testThread.join();

Categories

Resources