Reputation: 4136
As part of my unit tests, I am trying to mock the Thread.class isAlive() method to return true using Mockito. Below is my code:
final Thread mockThread = Mockito.mock(Thread.class);
Mockito.when(mockThread.isAlive()).thenReturn(true);
This is giving me the following exception on the second line:
Exception in thread "main" org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
I have used Mockito many times this way without issue. Is there some issue with mocking Thread.class? I have searched around with no luck.
Upvotes: 4
Views: 19834
Reputation: 131456
Thread.isAlive()
is declared with the final
modifier. It cannot be mocked by Mockito 1.
Use Powermock or Mockito 2 that adds this feature :
For a long time our users suffered a disbelief when Mockito refused to mock a final class. ... Mocking of final classes and methods is an incubating, opt-in feature
Or another way : change the way to unit test your class.
Do you really need to rely on isAlive()
to unit test ?
If you really need it, you could also use a wrapper class that composes a Thread
instance and that delegates the processing to the composed Thread
.
This could implement Runnable
for example.
In this way you could naturally mock the isAlive()
method of this wrapper class.
Upvotes: 3
Reputation: 140523
I give you a completely different perspective: get rid of interacting with threads in your production code completely.
Thing is: Thread is a pretty low level abstraction for multi-threading. 10, 15 years back we had only Threads, and where thus forced to use them.
But nowadays, you have a huge variety of abstractions that work on a higher level, like ExecutorServices, and Futures, and Promises, and ...
It might sound strange - but it might be more helpful for you to step back and consider not using threads the way you are using them today. You see, there are things like Same-Thread-Executors that allow you to turn your multi-threaded code into single threaded for testing - just by providing a different service to execute tasks.
That is the level of abstraction that you should strive for in 2017 - you shouldn't waste time on mocking low level final methods!
Upvotes: 2
Reputation: 4136
As others have pointed out, Thread's isAlive method is final and therefore cannot (and probably should not) not be mocked using Mockito.
A simple workaround was to create a private Runnable class in my unit test class with a run() method that just calls this.wait().
private class TestRunnable implements Runnable {
@Override
public void run() {
synchronized(this) {
try {
this.wait();
} catch (InterruptedException e) {
System.out.println("Interrupted!");
}
}
}
}
I am then able to create a thread in the unit test using an instance of this and the isAlive() method will always return true.
final TestRunnable testRunnable = new TestRunnable();
final Thread expectedThread = new Thread(testRunnable);
expectedThread.start();
Then later in the test..
assertTrue(expectedThread.isAlive());
And finally, To cleanup the thread, just call notify() on the Runnable instance (of course the thread will end when JUnit finishes too anyway)
synchronized(testRunnable) {
testRunnable.notifyAll(); // kill the Runnable (prob not necessary)
}
Upvotes: 3
Reputation: 64
It looks like the Thread.isAlive method is final, and final methods can not be mocked with Mockito.
Here is a related stackoverflow post.
Upvotes: 1