4

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.

java-addict301
  • 3,220
  • 2
  • 25
  • 37

4 Answers4

3

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.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Thanks, I didn't catch that isAlive() was final and that you couldn't mock final methods with Mockito (shoulda read the error more closely). Thanks for the suggestion. For my test case, I have added a private Runnable class that just calls wait() in a synchronize block. This way, I can call and have isAlive() be true, and terminate the thread by calling notify(). Thanks again for your quick answer. – java-addict301 Aug 16 '17 at 20:05
  • 1
    You are welcome :) I edited the answer to refer about Mockito 2. Your way to address the problem seems interesting. Don't hesitate to add an answer with it. It could help others. – davidxxx Aug 16 '17 at 20:11
  • @GhostCat much better :) – davidxxx Aug 17 '17 at 12:36
3

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)
}
java-addict301
  • 3,220
  • 2
  • 25
  • 37
  • 2
    Good answer for a newbie! Personally I'd just do `new Thread(() -> { while(true){} });` – Michael Aug 16 '17 at 20:34
  • @Michael I thought as you at first. But by thinking about it, unit tests has to be executed as fast as possible. In some cases, we may even parallelize them. `wait()` is more efficient as it doesn't consume a CPU Core/Thread, so I think that it should be favored over busy waiting. – davidxxx Aug 16 '17 at 20:40
  • 1
    @davidxxx Never prematurely optimise. :) – Michael Aug 16 '17 at 20:42
  • @Michael Right. But for unit test execution time, I violate the rule ;-) – davidxxx Aug 16 '17 at 20:45
  • @Michael Ah Lambda, we still need to become friends :) Agree with davidxxx's comment however which is why I went for the event driven paradigm. – java-addict301 Aug 16 '17 at 21:07
2

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!

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • @davidxxx I agree. But it is hard to give a specific example - given the fact that the OP is only asking about Thread.alive() - he doesn't give us insight into his production code - and there is already a fine, accepted answer. Not much point in inventing artificial examples then. – GhostCat Aug 17 '17 at 12:32
  • 1
    You are not wrong. Maybe, it would give idea for next questions and you would so an occasion to illustrate with a concrete case :) – davidxxx Aug 17 '17 at 12:35
  • @GhostCat Thanks for the insight. I at first considered avoiding using Thread.class directly for the reasons you mentioned but after more thought, I decided to use it. My use case is that I'm interacting with an API that limits requests/min and requests/day and charges you 'overages' for exceeding these limits, so the client must track its own usage. The problem is, the 'day' or 'minute' doesn't start until the first request is made. This rules out any scheduler service. I found it easier to use Thread directly with synchronization/blocking to throttle/keep track of remaining allowance. – java-addict301 Aug 17 '17 at 21:46
1

It looks like the Thread.isAlive method is final, and final methods can not be mocked with Mockito.

Here is a related stackoverflow post.

Kyle Scott
  • 64
  • 4
  • Thanks, the referenced post has a very helpful explanation of PowerMock's solution to this. – java-addict301 Aug 16 '17 at 20:02
  • 1
    Correction: the latest versions of Mockito **do** have support for mocking final classes/methods. It is experimental, but I still prefer experimental Mockito over ordinary PowerMock(ito) any second. – GhostCat Aug 17 '17 at 12:33