Hot questions for Using Mockito in multithreading

Top 10 Java Open Source / Mockito / multithreading

Question:

Introduction

I'm attempting to test a socket connection by sending a string from one thread to another, where server and client sockets are mocked with Mockito v1.9.5.

Here's the test I'm trying to run:

@Test
public void testConnection() {        
    //associate a mock server socket with the TCP Connection
    TcpSocketConnection connection = new TcpSocketConnection(mockServerSocket);
    try {
        //begin thread which listens for clients, then sends "Hello, world" to a connected
        //client.
        connection.listen();
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(mockTestClientSocket.getInputStream(), DEFAULT_CHARSET)
        );

        long startTime = System.nanoTime();
        for (long interval = 0;
                interval < TIMEOUT_TIME;
                interval = System.nanoTime() - startTime) {
            if (reader.ready()) {
                String receivedMessage = reader.readLine();
                assertEquals("Hello, world!", receivedMessage);
                mockTestClientSocket.close();
                connection.closeSocket();
                return;
            }
        }
        mockTestClientSocket.close();
        connection.closeSocket();
        fail("Failed to receive message.");
    } catch (IOException e) {
        fail(e.getMessage());
    }
}

The test runs until TIMEOUT_TIME and then the assertion that fails is the "Failed to receive message." I specify the behavior of the mocked objects here:

@Before
public void setup() {
    mockServerSocket = mock(ServerSocket.class);
    try {
        when(mockServerSocket.accept()).thenReturn(mockTestClientSocket);
    } catch (IOException e) {
        fail(e.getMessage());
    }

    mockTestClientSocket = mock(Socket.class);
    try {
        PipedOutputStream oStream = new PipedOutputStream();
        when(mockTestClientSocket.getOutputStream()).thenReturn(oStream);

        PipedInputStream iStream = new PipedInputStream(oStream);
        when(mockTestClientSocket.getInputStream()).thenReturn(iStream);

        when(mockTestClientSocket.isClosed()).thenReturn(false);
    } catch (IOException e) {
        fail(e.getMessage());
    }
}

Part of what I'm trying to test is the following run() within an inner class which is kicked off in the connection.listen():

class InnerListenerClass implements Runnable {
    @Override
    public void run() {
        try {
            clientSocket = socket.accept();
            writer = new OutputStreamWriter(
               clientSocket.getOutputStream(), DEFAULT_CHARSETNAME);
            out = new PrintWriter(writer, true);
            while (!clientSocket.isClosed()) {
                out.println("Hello, world!");
                Thread.sleep(MILLIS_BETWEEN_MESSAGES);
            }
        } catch (InterruptedException | IOException e) {
            LOG.debug(e.getMessage());
        }
    }

    public InnerListenerClass(final ServerSocket socket) {
        this.socket = socket;
    } 
}

And here's a portion of the TcpSocketConnection.java:

class TcpSocketConnection() {
    public TcpSocketConnection(final ServerSocket serverSocket) {
        checkNotNull(serverSocket);
        this.serverSocket = serverSocket;
    }
    ...
    public final void listen() throws IOException {
        listenerThread = new Thread(new InnerListenerClass(serverSocket));
        listenerThread.start();
    }
    ...
}
How it works in my head

This section is ignorable; I'm going to attempt to step through the process of my test to add some extra context to this question. Starting at the beginning of testConnection():

TcpSocketConnection connection = new TcpSocketConnection(mockServerSocket);

This creates a connection with a mocked ServerSocket associated with it. This creates a thread which kicks off with the following line:

clientSocket = socket.accept();

since socket above is a reference to mockServerSocket, Mockito knows to return a reference to a mock Socket called mockTestClientSocket because of this line:

when(mockServerSocket.accept()).thenReturn(mockTestClientSocket);

Next is the line below: NOTE: I believe this is where my understanding and reality diverge, as I believe based on debugging that this thread is hanging on creating this OutputStreamWriter object. I haven't figured out why.

writer = new OutputStreamWriter(clientSocket.getOutputStream(), DEFAULT_CHARSETNAME);

Make a new OutputStreamWriter given an OutputStream. Mockito knows what the output stream of the mocked client socket should look like because of these lines in the setup section:

PipedOutputStream oStream = new PipedOutputStream();                 
when(mockTestClientSocket.getOutputStream()).thenReturn(oStream);

Also, because the setup happens before the test, we know that our InputStream has a reference to this OutputStream because of this line:

PipedInputStream iStream = new PipedInputStream(oStream);

According to the documentation for this constructor, This "Creates a PipedInputStream so that it is connected to the piped output stream (oStream). Data bytes written to (oStream) will then be available as input from this stream."

The while loop in run() begins and causes "Hello, world!" to be sent out the OutputStream (and also received by the InputStream). Next, we wrap up the inputStream nicely:

BufferedReader reader = new BufferedReader(new InputStreamReader(mockTestClientSocket.getInputStream(), DEFAULT_CHARSET)); 

By the magic of Mockito, the mockTestClientSocket.getInputStream() call actually returns the iStream from earlier, because of the following line:

when(mockTestClientSocket.getInputStream()).thenReturn(iStream);   

So now we have a reader with an input stream, and that input stream is hooked up to an output stream. That output stream is hooked up to a PrintWriter which is printlning "Hello,world!"s. However, the reader never seems to even get ready().

Question

Why is the created listener thread hanging during creation of an OutputStreamWriter, and how can my Hello, World! string get sent properly from mocked socket to mocked client?

Apologies for being a Mockito/java.net.* newb and being a bit thick in general. I think I've included all the relevant portions of code, but if anything's unclear let me know.


Answer:

I could make your unit test pass by modifying 2 things in your code:

1. Mock mockServerSocket.accept() properly

Up to now, you mock mockServerSocket.accept() too early because mockTestClientSocket has not yet been set so it will return null, you need to set it first so your code should rather be:

mockServerSocket = mock(ServerSocket.class);
// Set it first
mockTestClientSocket = mock(Socket.class);

try {
    // Then mock it
    when(mockServerSocket.accept()).thenReturn(mockTestClientSocket);
} catch (IOException e) {
    fail(e.getMessage());
}
...
2. Synchronize your threads properly

As you launch a dedicated thread to manage your client socket, you need to synchronize your threads in order to make sure that your message will be ready to be read.

To do this you could:

  1. Simplify your code by calling reader.readLine() but it is a blocking approach since your current thread will wait as long as it is needed for the other thread to write the line (the message here).

The code could be:

BufferedReader reader = ...

String receivedMessage = reader.readLine();
assertEquals("Hello, world!", receivedMessage);
mockTestClientSocket.close();
connection.closeSocket();
  1. Set a value for TIMEOUT_TIME big enough even exaggeratedly big to make sure that the other thread will be ready, so for example as it is a value in nanoseconds, you could set it to 30 seconds so to 30_000_000_000L. If you don't set a value big enough, your test could be unstable in slow and/or overloaded and/or shared system such as server used for continuous integration.

Question:

I have a class that implements Runnable called DoThingInALoop. It is given to a second class that will create a thread out of it, call this thread Boss. The Boss can tell the runnable to quit and let the thread terminate. Later, it can create a new thread with that same DoThingInALoop.

When I am writing unit tests for the Boss I want to mock the DoThingInALoop because it is not the object under test. However, DoThingInALoop extends a class Loop and the code for Loop is actually being executed in the thread spawned by the Boss. That code of course runs into NullPointerExceptions because none of the member variables are set, because the object is mocked.

How can I prevent Java's Thread from "seeing through" the mock?

public class Loop implements Runnable {
    private final Object member = new Object();
    public final void run() {
        // This code runs, but it shouldn't
        synchronized (member) { // Throws NPE
            ...
        }
        // Hook for subclasses
        try {
            subclassRun();
        } finally {
            // Mandatory cleanup (unrelated to question)
        }
}

public class DoThingInALoop extends Loop {
    public void subclassRun() { ... }
    public void stopDoingThingsInALoop() {
        // Set instance member that on next loop iteration signals thread to return
    }
}

public class Boss {
    private final DoThingsInALoop toBeMocked;
    public Boss(final DoThingsInALoop toBeMocked) {
        this.toBeMocked = toBeMocked;
    }
    public void start() {
        // Simplified
        new Thread(toBeMocked).start();
    }
    public void stop() {
        toBeMocked.stopDoingThingsInALoop();
    }
}


public class TestClass {
    @Test
    public void aTest() {
        // Setup Mocks
        DoThingsInALoop mockLoop = mock(DoThingsInALoop.class);
        Boss boss = new Boss(mockLoop);

        // Run test
        boss.start();

        // After the above line runs, a new thread is started and
        // the run() method of `Loop` executes until the NPE
        // is hit when it attempts to access a member variable
        // which is of course not set because it is a mocked object

        ...
    }
}

Answer:

I think this is too much final for Mockito.

I would encapsulate the Thread execution in a new class that you can easily mock (let's call it Executor).

public class Executor {
    public void execute(Runnable runnable) {
        new Thread(runnable).start();
    }
}

And then use the Executor in the place when you create the Thread.

public class Boss {
    private final DoThingInALoop toBeMocked;
    private final Executor executor;

    public Boss(final Executor executor, final DoThingInALoop toBeMocked) {
        this.executor = executor;
        this.toBeMocked = toBeMocked;
    }

    public void start() {
        executor.execute(toBeMocked);
    }
}

In your test, you just need to mock the Executor.

    DoThingInALoop mockLoop = Mockito.mock(DoThingInALoop.class);
    Executor mockExecutor = Mockito.mock(Executor.class);
    Boss boss = new Boss(mockExecutor, mockLoop);

    boss.start();

    // No NPE aynymore
    verify(mockExecutor).execute(mockLoop);

Another option would be to try PowerMock

Question:

I have Thread which runs while the program runs and polls a queue and check whether it has object and if yes then it calls method on the object

Here is the code :

while(isRunning){
        synchronized (loginQueue) {
            if(loginQueue.peek() != null) {
                Object[] loginObjectWithConnection = loginQueue.poll();
                tryLogin(loginObjectWithConnection);
            }
        }
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
}

Here is the tryLogin method

private void tryLogin(Object[] loginObjectWithConnection) {
        LoginPacket packet = (LoginPacket)loginObjectWithConnection[0];
        Connection connection = (Connection)loginObjectWithConnection[1];

        try {
            if(playerDataService.arevalidCredentials(packet.getUserName(), packet.getPassword())) {

                if(!playerDataService.isPlayerBanned(packet.getUserName())){ //Player exists in the system

                    communicationService.sendTCP(connection, packetFactory.makeLoginFailurePacket(StringConstants.PLAYER_BANNED));

                } else{ //Player is not banned

                }
            } else { // Player does not exist
                communicationService.sendTCP(connection, packetFactory.makeLoginFailurePacket(StringConstants.INVALID_USER));
            }
        } catch (SQLException e) {
            communicationService.sendTCP(connection, packetFactory.makeLoginFailurePacket(StringConstants.SERVER_ERROR));
            e.printStackTrace();
        }
}

Now my problem is that I want to test the invocations of these service methods but when I run the unit tests they won't work as it takes time to reach the point of tryLogin and till then JUnit fails. I tries using Thread.sleep() but I know it is not the right way to do it as it fails sometimes and pass sometimes.

Here is what I have in my Unit Test

@Test
public void theExpectedMessageShouldBeSentIfUserIsBanned() throws InterruptedException, SQLException {
    //Arrange
    when(moqLoginQueue.peek()).thenReturn(object);
    when(moqLoginQueue.poll()).thenReturn(object);
    LoginFailurePacket packet = new LoginFailurePacket(StringConstants.PLAYER_BANNED);
    when(moqPacketFactory.makeLoginFailurePacket(StringConstants.PLAYER_BANNED)).thenReturn(packet);
    when(moqPlayerDataService.arevalidCredentials(anyString(), anyString())).thenReturn(true);
    when(moqPlayerDataService.isPlayerBanned(anyString())).thenReturn(true);

    //Act
    loginManager.start();
    Thread.sleep(10); //Dirty hack -.-

    //Assert
    verify(moqCommunicationService).sendTCP(any(Connection.class), eq(packet));
}

Answer:

The system is untestable in the current form: among good test qualities there are:

  • easy for other programmers to undertsand
  • hard for other programmers to break
  • fast to run

The piece of logic you want to test is LoginManager.tryLogin, which is private in your snippet. If you want to publicly document it (tests are kind of documentation: they state how the system should behave), it has to be public.

I suggest to move all that logic to a method in a new class: Authentication.attempt() (I suggest an immutable object and a method that does not take any argument - someone says the optimal number of arguments in OO design is zero).

Now that testing is feasible, I also think you should get rid of all that code in LoginManager.start(): simply use an ExecutorService and submit authentication attempts - this way you'll have a faster program and less code to test, because the hard (and tricky) part is managed by Java.

Question:

I'm trying to use Mockito and JUnit to test a multithreaded application. Here's some of the code in question:

ArgumentCaptor<MessageCreator> messageCaptor = ArgumentCaptor.forClass(MessageCreator.class);

jmsHandler.put(message);

Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture());

The jmsHandler.put(message) line puts a String into the application, which goes onto a BlockingQueue and starts with the multithreading parts. I then wait on the method to execute 4 times over the next 10 seconds and capture the results.

The application should spit out 4 instances of MessageCreator, which, for my purposes, is just an object containing a String that I'll then compare to the expected output. The logging during the test confirms that the 4 messages are being created.

When I tried to loop through the ArgumentCaptor's getAllValues() method to check the results, though, I noticed that the List is duplicating my program's output literally millions of times. It should have 4 objects in it, but the last run had 6,984,988.

This number seems to be variable to some small extent, but it changes drastically when I play around with the test timings in debug mode. For example, if I set a breakpoint at the jmsHandler line, step over that, and wait for the application to finish processing before even starting the Mockito.verify(...) step, the List size plummets to a "mere" 158,636 objects.

Has anyone else run into this kind of issue before? Please let me know if I can provide any more details.

EDIT: Here's a self-contained example of the test and program structure:

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class MultiThreadTest {
    private Input inputHandler;
    @Mock
    private JmsTemplate mockJmsTemplate;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(10);

        inputHandler = new Input();
        inputHandler.setQueue(queue);

        Output outputHandler = new Output();
        outputHandler.setQueue(queue);
        outputHandler.setJmsTemplate(mockJmsTemplate);
        new Thread(outputHandler).start();
    }

    @Test
    public void testMessage() {
        ArgumentCaptor<OutputMessageCreator> messageCaptor = ArgumentCaptor.forClass(OutputMessageCreator.class);

        String inMessage = "testMessage";

        List<String> expectedMessages = new ArrayList<String>(4);

        inputHandler.put(inMessage);

        Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture());
        System.out.println("Number: " + messageCaptor.getAllValues().size());
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(0)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(1)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(2)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(3)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(4)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(5)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(6)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(7)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(8)));

        List<String> outMsgs = new ArrayList<String>();
        for (OutputMessageCreator creator : messageCaptor.getAllValues()) {
            outMsgs.add(creator.getMsg());
        }
        assertEquals(expectedMessages, outMsgs);
    }

    private class Input {
        private BlockingQueue<String> queue;

        public void put(String msg) {
            try {
                queue.put(msg);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void setQueue(BlockingQueue<String> queue) {
            this.queue = queue;
        }
    }

    private class Output implements Runnable {
        private BlockingQueue<String> queue;
        private JmsTemplate jmsTemplate;
        private int counter = 1;

        @Override
        public void run() {
            while (true) {
                String msg = null;
                try {
                    msg = queue.take();
                    String[] messagesOut = new String[4];
                    for (int i = 0; i < 4; i++) {
                        messagesOut[i] = msg + "-" + counter++;
                    }

                    for (String messageOut : messagesOut) {
                        System.out.println(messageOut);
                        jmsTemplate.send(new OutputMessageCreator(messageOut));
                        Thread.sleep(2000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void setQueue(BlockingQueue<String> queue) {
            this.queue = queue;
        }

        public void setJmsTemplate(JmsTemplate jmsTemplate) {
            this.jmsTemplate = jmsTemplate;
        }
    }

    private class OutputMessageCreator implements MessageCreator {
        private String msg;

        public OutputMessageCreator(String msg) {
            this.msg = msg;
        }

        @Override
        public Message createMessage(Session session) throws JMSException {
            TextMessage message = session.createTextMessage();
            message.setText(msg);
            return message;
        }

        public String getMsg() {
            return msg;
        }
    }
}

Here's the output from running that test:

testMessage-1
testMessage-2
testMessage-3
testMessage-4
Number: 5392168
Equal: true
Equal: false
Equal: false
Equal: false
Equal: true
Equal: false
Equal: false
Equal: false
Equal: true

Answer:

It looks like this was a bug in Mockito at some point:

https://github.com/mockito/mockito/issues/345

https://github.com/mockito/mockito/issues/379

The issues seem to imply this was fixed in Mockito 2 or 2.1, but I am using 2.0.41-beta and tried 2.4.0 and 2.8.9 and got the same results. In some of the comments of the github issues, it appears that there's a work around of sorts.

This line of the code:

Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture());

can be replaced with this:

try {
    Thread.sleep(10000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

Mockito.verify(mockJmsTemplate, Mockito.times(4)).send(messageCaptor.capture());

I've commented on issue 379 to see if the fix was actually released, but it seems like this work around will do the trick for now.

Question:

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?


Answer:

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.

Question:

I have a below scenario when setView is called then Presenter fetches some data over the network on a new thread. Test fails by giving this reason - Actually, there were zero interactions with this mock. But it should pass if interaction gets verified.

Testcase
@Test
public void checkUnoRate() {
    ratePresenter.setView(rateView,Constants.UNO);
    verify(rateView,times(1)).showRate(new Rate());
}
Inside "ratePresenter.setView"
Call<UnoRate> call1 = ratesAPI.getUnoRate();
            call1.enqueue(new Callback<UnoRate>() {
                @Override
                public void onResponse(Call<UnoRate> call,Response<UnoRate> response) {
                    UnoRate unoRate = response.body();
                    Rate rate = new Rate();
                    rate.setBuyRate(unoRate.getBuy());
                    rate.setSellRate(unoRate.getSell());
                    rate.setFee(0);
                    rateView.showRate(rate);
                    }

               });

Answer:

One very simple solution is to use Mockito's verification with timeout feature. This will retry the verification repeatedly up until the timeout, looking for the condition to pass at some point or another.

@Test
public void checkUnoRate() {
    ratePresenter.setView(rateView,Constants.UNO);
    verify(rateView, timeout(100).times(1)).showRate(new Rate());
}

The docs, however, warn against it: "This feature should be used rarely - figure out a better way of testing your multi-threaded system." This is probably because you're introducing a new aspect--time--as a proxy for the thing you really want to check, which is that all of the queues have been processed. You could even imagine a busy enough VM where a conservative timeout could cause the test to flake in automated testing systems but that works fine on development machines.

If feasible, you could switch your ratesAPI to use a synchronous executor, or instead you could add methods needed to your API accessor to block the test thread until all calls have returned asynchronously:

@Test
public void checkUnoRate() {
    ratePresenter.setView(rateView,Constants.UNO);
    ratesAPI.flush(); // Implement this to perform a Thread.join on the callback thread,
                      // or otherwise wait until all callbacks have been called.
    verify(rateView,times(1)).showRate(new Rate());
}

Or, to remove multithreading and external API interactions from your test, simulate the callback synchronously:

@Mock RatesAPI ratesApiMock;
@Mock Call<UnoRate> unoRateCallMock;
@Captor Callback<UnoRate> unoRateCallbackCaptor;

@Test
public void checkUnoRate() {
    // Set up mock.
    when(ratesApiMock.getUnoRate()).thenReturn(unoRateCallMock);

    // Perform the action.
    ratePresenter.setView(rateView,Constants.UNO);

    // Verify nothing happens yet.
    verify(rateView, never()).showRate(any());

    // Capture and trigger the callback.
    verify(unoRateCallMock).enqueue(unoRateCallbackCaptor.capture());
    unoRateCallbackCaptor.getValue().onResponse(yourCall, yourResponse);

    // Verify the asynchronous action.
    verify(rateView,times(1)).showRate(new Rate());
}

As a side note, eventually you'll probably want to verify against a different parameter than new Rate(). Mockito compares via equals methods when not using Mockito matchers.

Question:

I am trying creating a unit test for my multithreaded code.

My current code snippet is like this:

verify(someObject, times(2)).someMethod(captor.capture());
List<SomeObject> list = captor.getAllValues();
assertThat(list.get(0)).isEqualTo(...
assertThat(list.get(1)).isEqualTo(...

Now someMethod is called in two separate threads, so the order of captured arguments is nondeterministic. I was wondering if there was a way to assert these arguments without any particular order.

Of course I could write a custom Comparator and sort the list beforehand, but I was wondering if there was a simpler way than this.

Thanks!


Answer:

Simply check that the list contains the elements, independently from the order:

assertThat(list, hasItem(...));
assertThat(list, hasItem(...));

Question:

I have a class MyThread which either extends Thread or implements Runnable interface. The MyThread class constructors and some private methods and run() method defined.

What is the right way to write junit test cases for the class? Can I write test cases for the run() method by directly invoking it within test methods or should I create an instance of the thread and do thread.start()?


Answer:

Don't extend Thread. Implement Runnable. Test the run() method the same way you would test any "ordinary" method.

The obvious benefit of this approach is that you don't need to deal with concurrency at all.

Question:

My class under test has a few dependencies. All of these provide setListener() as a way to receiving notification from their non-blocking operations.

I implemented a blocking method that aggregates the results from all the non-blocking ops. Which mean I have to register the listeners using such setListener() methods, and wait for the callbacks.

How should I mock/fake these dependencies in my unit test? I could subclass them and implement setListener() and fire the callbacks as necessary. But let's say some of these deps are final class. Also, I think there might be something I could use from Mockito?

Conceptual code (untested):

public void blockingMethod() {
  CountDownLatch signal = new CountDownLatch(2);

  dep1.setListener(new Dep1Listener() {
    @Override public onResult(int result) {
      signal.countDown();
    }
  });
  dep1.calculateValue1();

  dep2.setListener(new Dep2Listener() {
    @Override public onResult(int result) {
      signal.countDown();
    }
  });
  dep2.calculateValue2();

  signal.await();
  return combinedResult;
}

Answer:

I would create concrete implementations of your dependencies that return fixed values. I wouldn't subclass existing classes, instead create minimal implementations of your interfaces. If you don't have interfaces defined for the dependencies, create them.

Mocking may work, but the tests would be harder to read. As soon as a mock needs to hold onto an argument (i.e. your listener) and do something with it later, it becomes challenging.