0

Background Info

I have a thread. It's a dedicated thread to continuously take out a task from a queue and write to a persistent repository. So it's code is like this.

public class Processor extends Thread {
    //Context saves reference to the task queue and the write backEnd service
    public GeneralProcessor(Context context){initProcessor( context,  Type.GENERAL);}
    public void run() {
        ...
        synchronized (Processor.class) {
            Thread curThread=currentThread();
            Context context=getContext();
            ConcurrentLinkedQueue<Task> taskQue =context.getTasks();
            if (taskQue.size() > 0) {
                Task t = taskQue.poll();
                Transaction ts = new Transaction();
                //all works to copy Task's member values to Transaction, and add other values to this transaction
                //...
                context.getService().save(ts);//this is the line I want to monitor. This is also related to issue in some way.

            }
        }
    }
}

The Issue

But there is an issue when I wrote a unit test for this class. My original unit test is this.

@ExtendWith(MockitoExtension.class)
public class GeneralProcessorTest {
    @InjectMocks
    private GeneralProcessor generalProcessor;
    @Mock
    private Context context;
    @Spy
    private ConcurrentLinkedQueue<Task> tasks;
    @Mock
    private TransactionRepository transactionRepository;
    @Captor
    private ArgumentCaptor<Transaction> transactionArgumentCaptor;
    @Mock
    private TransactionService transactionService;


   @BeforeEach
    void setup() {
        //transactionService=new TransactionServiceImpl(transactionRepository);
    }

    @Test
    @SneakyThrows
    void should_match_save_times_single_thread() {
        //given
        CountDownLatch latch=new CountDownLatch(0);
        this.tasks.add(new Task(10));
        //stub code
        when(context.getTasks()).thenReturn(tasks);
        when(context.getService()).thenReturn(transactionService);
        //when
        generalProcessor.start();
        latch.await(1, TimeUnit.SECONDS);
        //then
        //the issue happened here!
        verify(transactionService).save(transactionArgumentCaptor.capture());
        List<Transaction> capturedArguments = transactionArgumentCaptor.getAllValues();
        assertEquals(capturedArguments.size(),1);
    }

But I got:

Wanted but not invoked:
transactionService.save(
    <Capturing argument>
);
at com.example.demo.GeneralProcessorTest.should_match_save_times_single_thread(GeneralProcessorTest.java:65)
Actually, there were zero interactions with this mock.

In fact, I tried to init transactionService with new. But Mockito told me that in verify I can only use Mock object.

So I am confused. Is there any way to let me use verify while at the same time keep transactionService working as a normal object? Any info is appreciated.

Yu Fang
  • 520
  • 5
  • 17
  • Why don't you call ` generalProcessor.run()` directly instead of ` generalProcessor.start()`? – talex Oct 11 '22 at 09:57
  • @talex In this way, it causes that the test doesn't stop--the circle doesn't stop circling. I call generalProcessor.run() and disable latch, but it's not better. Not sure whether a thread produces this – Yu Fang Oct 11 '22 at 10:23
  • Perhaps you should call `generalProcessor.join()` instead of latch. – talex Oct 11 '22 at 11:11
  • Does this help? https://stackoverflow.com/questions/74027324/why-is-my-class-not-using-my-mock-in-unit-test – knittl Oct 11 '22 at 11:26
  • Does this answer your question? [Initialising mock objects - MockIto](https://stackoverflow.com/questions/15494926/initialising-mock-objects-mockito) – pringi Oct 13 '22 at 11:20

0 Answers0