How to test runnable which executed another runnable - java

I have some runnable where one of the parameter is delegator with taskExecutor to execute another runnable:
#Override
public void run() {
try {
doTask(messageId);
} catch (Exception e) {
count++;
if (count < 4) {
delegatedTransactionalAsyncTaskExecutor.execute(this);
} else {
delegatedTransactionalAsyncTaskExecutor.execute(getOnExceedErrorTask(messageId));
}
throw new RuntimeException(e);
}
}
how should I test this ?

It seems that delegatedTransactionalAsyncTaskExecutor is a field in your class.
In order to ensure that you can test it, you have to use dependency injection, like this:
class UnderTest {
private final Whatever delegatedTransactionalAsyncTaskExecutor;
UnderTest(Whatever delegatedTransactionalAsyncTaskExecutor) {
this.delegatedTransactionalAsyncTaskExecutor = delegatedTransactionalAsyncTaskExecutor;
...
And now, you can use mocking frameworks to create objects of that Whatever class. Mocks allow you to specify the method calls you expect to happen; and then, you can verify later on that those calls really took place.
In other words: you prepare a mock; then you invoke run() ... and afterwards you check that those calls you were looking for actually happened. And of course for the whole thing to work, you must be able to inject those mocks into your "class under test".

Related

Mockito verify fails in second unit test

I am using Mockito together to JUnit to implement unit tests for a class in an Android project.The problem is that I call Mockito.verify in two consequent tests where the tests are exactly same (to make sure that I am using Mockito correctly) but the interesting thing is that verify in second test always fails.I suspect that some operations need to be done before each test using #before annotation or so, that I have missed.Here are some code snippet about what I am doing.
I use Android Studio 3.4.1, Mockito 2.7.22 and JUnit 4.12.
#Test
public void test_onStart_do_nothing() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
verify(mockedZConnection, times(1)).connect();
}
#Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
// Line above is the line that error message points to!
verify(mockedZConnection, times(1)).connect();
}
Here comes the function under test
public void initConnection(ZConnection connection) {
Log.d(TAG,"initConnection()");
if (mConnection == null) {
mConnection = connection;
}
if (!mActive) {
mActive = true;
if (mThread == null || !mThread.isAlive()) {
mThread = new Thread(new Runnable() {
#Override
public void run() {
// The code here runs in a background thread.
Looper.prepare();
mTHandler = new Handler();
try {
mConnection.connect();
} catch (IOException e) {
Intent i = null;
i = new Intent(ZConnectionService.UI_NOTCONNECTED);
i.setPackage(getApplicationContext().getPackageName());
getApplicationContext().sendBroadcast(i);
e.printStackTrace();
// Stop the services all together.
stopSelf();
}
Looper.loop();
}
});
mThread.start();
}
}
}
I expect that both tests should pass without any problem. In fact, both tests are passed when I ran them individually, but they fail when I run the whole suite and the error is:
Wanted but not invoked:
mockedZinkConnection.connect();
-> at com.app.z.ZConnectionServiceUnitTest.test_onStart_throw_IO_exceptioon(ZConnectionServiceUnitTest.java:207)
Actually, there were zero interactions with this mock.
I think the issue is a multithreading one.
When you call initConnection, it calls mConnection.connect() in a Thread
The problem you are having is that this Thread takes some time to complete and you end up calling verify(mockedZConnection, times(1)).connect(); before the Thread actually reached the connect() call.
A way to make sure about it is to join the Thread after you start it, it will wait until the Thread has finished before continuing:
mThread.start();
try {
mThread.join();
} catch (InterruptedException i) {
i.printStackTrace();
}
Now both tests should work.
This of course is not acceptable in the code, because it negated the use of a Thread. You will need an other way to test it.
A way I can think of would be to wait for the Thread to complete in your test before checking the mock:
#Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
// Wait for the Thread to complete
while(zConnectionService.mThread.isAlive()) {
Thread.sleep(100);
}
verify(mockedZConnection, times(1)).connect();
}
Tried and it works fine for me. Not sure it is a best practice though as you need to make public some internals of your class, which violates encapsulation
maybe having a package protected isThreadAlive() method on your ZConnectionService class could be acceptable
boolean isThreadAlive() {
return mThread.isAlive();
}
and the loop in the test
while(zConnectionService.isThreadAlive()) {
Thread.sleep(100);
}

how to unit test this threaded code

I have a class that normally runs in a thread that processes data forever until another thread invokes stop() on it. The problem I have is that the unit test gets stuck in the main loop since the test is single threaded and I want to keep it that way. How can I unit test this without polluting the code? this class is part of a critical system and needs to be as simple and efficient as possible so I want to avoid unit testing hacks in the code
public class MyClass implements Runnable {
boolean running;
public void run() {
//foo is injected from the outside
foo.start();
work();
foo.end();
}
public void work() {
running = true;
while(running) { //main loop
bar.process(); //bar is injected from the outside
}
}
public void stop() {
running = false;
}
}
Basically what I'm doing in the test is mocking out foo and bar and I call run() from the unit test, where later I verify in the bar mock whether process was actually called. I also verify that in the foo mock start() and end() got called. The problem is that because I really want to keep the test single threaded, the test thread gets stuck forever in the while(running) loop.
Some things I have tried and don't like
add some VM property to trigger a break at the end of the iteration of the main loop. The problem with this is that as mentioned, this code is very critical and I want to keep the code clear of unit-testing clutter. I don't want production code evaluating in every iteration some VM property that I only use at development time
use the bar mock to invoke stop() on its call of process(). Mockito doesn't like the fact that I call another class' method and throws an exception
externalize the control of the mainloop. so instead of checking a boolean in the while, I call a method that returns whether to continue or not. And this loop-control object can be injected from the outside, that way in the unit test i can make the control method return true and then false to get a single iteration out of the loop. This complexifies the code quite a bit and makes it unnatural and harder to read plus it only would make any sense in a unit test context
Are there any other suggestions or common patterns to test Runnables, or maybe a better way to write my code so that testing it is easier?
I suggest making a change which would both make your code more by-the-book and allow breaking out in a single thread:
while (!Thread.currentThread().isInterrupted() && running) {
bar.process();
}
You can call Thread.currentThread().interrupt() before you run this code; the thread's interrupted flag will be set and the method isInterrupted() will return true.
This is more by-the-book because it makes your main loop participate in Java's interruption mechanism.
Create an interface for the class of bar that only contains the method process. Your MyClass seems generic enough so that this would be OK. Then, instead of mocking bar, create your own implementation dummy (or mock, whatever you like to call it). This will then call the stop method and your process method is only called once. You can check whether BarMock.process was called with an assertion using its isCalled method. Also, I would suggest an isRunning method for your MyClass so that you can check whether it was stopped.
public interface Processable {
public void process();
}
public class BarMock implements Processable {
private MyClass clazz;
private boolean called;
public BarMock(MyClass clazz) {
this.clazz = clazz;
called = false;
}
#Override
public void process() {
// you can assertTrue(clazz.isRunning()) here, if required
called = true;
clazz.stop();
}
public boolean isCalled() {
return called;
}
}
public class MyClass implements Runnable {
boolean running;
public void run() {
// foo is injected from the outside
foo.start();
work();
foo.end();
}
public void work() {
running = true;
while (running) { // main loop
bar.process(); // bar is injected from the outside
}
}
public void stop() {
running = false;
}
public boolean isRunning() {
return running;
}
}
I think this method has three advantages over the one suggested by William F. Jameson, but also disadvantages:
Advantages:
You can test whether your process method was actually called
You don't have to add code that you never use during the actual program run
You can test whether the stop method really stops
Disadvantages:
You have to introduce an interface
Need to test BarMock class, too
That said, I'd still prefer introducting the interface, since it doesn't pollute your code too much and therefore is a small price to pay.

JUnit test of a java asyncron method

Today I had to write a method which get a String as a parameter, make a new thread and write it out to the consol after 5 seconds waiting, so something like this:
public void exampleMethod(final String str){
Runnable myRunnable = new Runnable(){
public void run(){
try {
Thread.sleep(5000);
System.out.println(str);
} catch (InterruptedException e) {
//handling of the exception
}
}
};
Thread thread = new Thread(myRunnable);
thread.start();
//some other things to do
}
My question is: How can I test and what should I test in here with JUnit?
Thank you!
There is nothing complex in this method. You are only using standard API-methods: Thread.sleep, System.out.println, ...
The parameter is just printed, you don't modify it nor use it for a calculation or another method.
There are no side-effects to your own written code, just to the STL.
And there is no result of the method, which you could test.
In my opinion it is not necessary and not simply possible to test it.
The only thing you could test (and even that wouldn't be trivial), is, if after an amount of time the String is printed.
[...] JUnit finishes execution while the thread is still alive. There could have been problems down the line, toward the end of that thread's execution, but your test would never reflect it.
The problem lies in JUnit's TestRunner. It isn't designed to look for Runnable instances and wait around to report on their activities. It fires them off and forgets about them. For this reason, multithreaded unit tests in JUnit have been nearly impossible to write and maintain.
Well, the source - this article - is from 2003 and there's no guarantee that this hasn't been fixed yet, but you may try it out yourself.
My suggestion would be:
Run your code and measure the time it takes. Then add some 1000 milliseconds and but a Thread.sleep(executionTime+1000); after you started you asynchronous task. Not that elegant, but should work in practice. If you want more elegance here (and waste less time), you may want to look for framework that provide a solution.
...Or if you start your Thread directly in the test, you may also use Thread.join to wait, but you will have cases, where you aren't able to do that.
EDIT:
Also check this article, which could provide a solution to pipe those errors to the main thread:
public class AsynchTester{
private Thread thread;
private volatile Error error;
private volatile RuntimeException runtimeExc;
public AsynchTester(final Runnable runnable) {
thread = new Thread(new Runnable() {
#Override
public void run() {
try {
runnable.run();
} catch (Error e) {
error = e;
} catch (RuntimeException e) {
runtimeExc = e;
}
}
});
}
public void start() {
thread.start();
}
public void test() throws InterruptedException {
thread.join();
if (error != null)
throw error;
if (runtimeExc != null)
throw runtimeExc;
}
}
Use it like that:
#Test
public void test() throws InterruptedException {
AsynchTester tester = new AsynchTester(new Runnable() {
#Override
public void run() {
//async code
}
});
tester.start();
tester.test();
}
The issue here is that you are trying to test an interaction instead of a simple returned result or a state change. However, that does not mean it can't be done.
The standard out PrintStream can be replaced with System.setOut(). You can inject your own mock implementation that would allow you verify that the String was written to the stream. You just have to be careful, since this changes the global state, it might effect other code or tests that rely on standard output. At a minimum, you will have to put back the original stream. But things might get more complicated if tests are running in parallel.
This takes us to the next issue, the sleep. There isn't a strong guarantee to how long a sleep will block. This means your test would have to provide some buffer to ensure that the thread had time to write the String before checking the state of the mock stream. You don't want your test to be flaky because of some execution timing jitter. So you would have to decide what buffer you would consider acceptable.
An alternative approach would be to change the implementation of the code so that it is easier to test.
The simplest way to do this is to remove all the static dependencies. Instead of explicitly referencing System.out, the class could be initialized with with an PrintStream to write to. Additionally, you could define an interface that would wrap Thread.sleep(). For testing purposes, you can initialize the class with the mock stream and no-op implementation of the sleep interface. However, you may still have some timing issues as you need the newly created thread to execute before continuing the test.
The other thing you can do is take a step back and decide how much you care about this code being tested. There are only 4 interesting lines of code in this sample and none of them are complicated. Having a code review could be sufficient to ensure there are no bugs.
However, if the business logic is more complicate than writing to standard out, you might decided that testing that is important. The good news is that scheduling a task in an executor is straight forward and that is the part that is making the testing hard. You could make an abstraction that encompasses the scheduling of the task in a background thread. Then provide yourself with more direct access to the business logic in order to test that.
I have often solved that, by providing a ResultTarget which implements an interface IResultTarget to the thread,
In productive code the result will be a list that contains the calculation result. (or null)
In your unit test the ResultTarget is the unit test class itself, which then easily can check the received result.
public Interface IResultTarget {
List getResult();
}
public void ThreadTest extends TestCase implements IResultTarget {
List result;
public List getResult(
return this.result;
}
public void testThread() {
MyRunnable myRunnable= new MyRunnable ();
myRunnable.setResultTarget(this);
Thread thread = new Thread(myRunnable);
thread .start();
Thread.sleep(5 * 1000);
// expecting one element as result of the work of myRunnable.
assertEquals(1, result.size());
}
}

Mockito: wait for an invocation that matches arguments

I'm writing a selenium test and verifying the server behavior with mockito. Specifically, when a button is clicked, I want to make sure the page controller calls a particular method on a dependency which I've mocked.
Because it is a selenium test, I need to wait for the mock to be invoked in another thread, so I'm using mockito timeout.
verify(myMock, timeout(5000).times(1)).myMethod("expectedArg");
The trouble that I'm having is that myMethod is called many times... rather than waiting for an invocation that matches the expected arguments, timeout only waits for the first invocation.
If I use Thread.sleep(50000) rather than timeout(50000), it works as expected... but that's dirty so I'm hoping to avoid it.
How do I wait for myMethod to be invoked with the expected input?
If you are able to set a fixed number of calls to expect, it can be done with an ArgumentCaptor:
import static org.hamcrest.CoreMatchers.hasItem;
#Captor ArgumentCaptor<String> arg;
#Before
public void setUp() throws Exception {
// init the #Captor
initMocks(this);
}
#Test
public void testWithTimeoutCallOrderDoesntMatter() throws Exception {
// there must be exactly 99 calls
verify(myMock, timeout(5000).times(99)).myMethod(arg.capture());
assertThat(arg.getAllValues(), hasItem("expectedArg"));
}
Another way is to specify all the expected values to verify, but those need to be provided in the exact order that they are invoked. The difference to the above solution is that this doesn't fail even if the mock is additionally called with some non-verified arguments. In other words, no need to know the number of total invocations. Code example:
#Test
public void testWithTimeoutFollowingCallsDoNotMatter() throws Exception {
// the order until expected arg is specific
verify(callback, timeout(5000)).call("firstExpectedArg");
verify(callback, timeout(5000)).call("expectedArg");
// no need to tell more, if additional calls come after the expected arg
// verify(callback, timeout(5000)).call("randomArg");
}
This is not a super clean solution but you can do this (XX is the supposed return type here):
final CountDownLatch latch = new CountDownLatch(1);
doReturn(new Answer<XX>()
{
#Override
public XX answer(InvocationOnMock invocation)
{
latch.countDown();
return someInstanceOfXX;
}
}
).when(myMock).myMethod("expectedArg");
Then, to test if the method is called, do:
try {
assertTrue(latch.await(5L, TimeUnit.SECONDS));
} catch (InterruptedException e) {
// Urgh... Failed. Deal with it and:
Thread.currentThread().interrupt();
}

How can I add similar functionality to a number of methods in java?

I have a lot of methods for logging, like logSomeAction, logAnotherAction etc.
Now I want all these methods make a small pause after printing messages (Thread.sleep).
If I do it manually, I would do something like this:
//before:
public static void logSomeAction () {
System.out.println (msg(SOME_ACTION));
}
//after:
public static void logSomeAction () {
System.out.println (msg(SOME_ACTION));
try {
Thread.sleep (2000);
} catch (InterruptedException ignored) { }
}
I remember that Java has proxy classes and some other magic-making tools. Is there any way avoid copy-n-pasting N sleep-blocks to N logging methods?
You could use Aspects to add extra "orthogonal" functionality to your methods.
If that sounds too esoteric, a simpler, down-to-earth solution would be to add the sleep in a separate method, then call that method in each of your logging methods. The first time you do this, you need to touch each method, but the next time if you want to modify the extra behaviour or add something else, you can do it in one single place.
It looks like you want to use Aspect Oriented Programming. You could use Spring for AOP, or AspectJ.
The OP mentions in a comment that the preferred solution is to use plain java proxies. The current code is implemented as static methods - for java proxies to be of any use, the logger class will need to be reworked as an interface. Something like this:
public interface SomeActionLogger
{
void logSomeAction();
void logSomeOtherAction();
// etc..
}
You then create your concrete implementation
public class SystemOutActionLogger implements SomeActionLogger
{
public void logSomeAction () {
System.out.println (msg(SOME_ACTION));
}
}
You can then have Java proxies wrap the SomeActionLogger interface
class DelayAfterInvocationHandler implements InvocationHandler
{
private Object delegate;
private int duration;
DelayAfterInvocationHandler(Object delegate, int duration)
{
this.delegate = delegate;
this.duration = duration;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object returnValue = method.invoke(delegate, args);
Thread.sleep(duration);
// you may want to catch InterruptedEception
return returnValue;
}
}
To hide some of the not-so-pretty proxy code, you can then have a method that wraps your logger to create the delay, e.g.
public ActionLogger addDelay(SomeActionLogger logger, int delay)
{
return (ActionLogger)Proxy.newProxyInstance(
impl.getClass().getClassLoader(),
new Class[] { SomeActionLogger.class },
new DelayAfterInvocationHandler(logger, delay));
}
So you then write
SomeActionLogger log = addDelay(new SystemOutActionLogger(), 2000);
Note that the DelayInvocationHandler is orthogonal to the logging interface - it can be used to add delay to any interface. You might then create a generic wrapping method like this:
public <T> T addDelay(T delegate, int delay, Class<T> interfaceType)
{
return (T)Proxy.newProxyInstance(
delegate.getClass().getClassLoader(),
new Class[] { type },
new DelayAfterInvocationHandler(delegate, delay));
}
Make a utility class that has a static SleepFor method which includes your try ... catch block and call that from every method you want a sleep in?
Replace all the System.out.println(msg(SOME_ACTION)); with printAndWait(SOME_ACTION);
You should be able to do that with find and replace.
Then create a method
public static void printAndWait(Object someAction) {
System.out.println (msg(someAction));
try {
Thread.sleep (2000);
} catch (InterruptedException ignored) {
Thread.currentThread.interrupt();
}
}
That way the code appears once and you can change it easily in one place.
Replace all of your logSomeAction() methods with a single logAction(Action a) method. This way, when you add more actions in the future, you will not be repeating your code for handling the action log and the thread sleep.

Categories