Search code examples
androidunit-testingmockitostatic-methods

Can not verify a method which is called from a static method


I have to verify that a method is called from a static method.

// Class name: PerformJob
// Method to be tested
public static void job(Context context) {
   JobScheduler jobScheduler = (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE);
   if (jobScheduler != null) {
      JobInfo pendingJob = jobScheduler.getPendingJob(Job.POLLING_JOB_ID);
   }
}

My tested code:I want to verify that when jobScheduler instance is not null, it will call getPendingJob().

@PrepareForTest({Context.class, PerformJob.class, JobScheduler.class, JobInfo.class})
@Mock
Context mContext;
@Test
void jobTest(){
   mockStatic(PerformJob.class);
   JobScheduler scheduler = mock(JobScheduler.class);
   JobInfo pendingJob = mock(JobInfo.class)
   when(mContext.getSystemService(JOB_SCHEDULING_SERVICE).thenReturn(scheduler);
   when(scheduler.getPendingJob(Job.POLLING_JOB_ID)).thenReturn(pendingJob);
   PerformJob.job(mContext);
   
   // Job.POLLING_JOB_ID is an Int
   verify(scheduler, times(1)).getPendingJob(Job.POLLING_JOB_ID); // It fails.
   
}

Note: PerformJob is a static class

Error message is: "Wanted but not invoked... Actually there are zero interaction with this mock."

What is wrong here? Why verification failed? Please help. I am newbie. I searched same types of problems but can not get any similar problem solutions. Waiting for help. Thanks


Solution

  • The first thing is that you don't need to mock PerformJob class and the class containing the PerformJob class.

    Consider the following: Let's say that you have a class called Abc and inside the Abc class you have a static class called JobPerformer which contains a static method called job like below:

    public class Abc {
    
      public static class JobPerformer {
        public static void job(Context context) {
            JobScheduler jobScheduler = (JobScheduler) 
            context.getSystemService(JOB_SCHEDULER_SERVICE);
            if (jobScheduler != null) {
              JobInfo pendingJob = jobScheduler.getPendingJob(Job.POLLING_JOB_ID);
            }
        }
      }
    }
    

    Now in the test class all you need is this:

    private Abc subject;
    
    @Mock
    private Context mContext;
    
    @Before
    public void setUp() {
        subject = new Abc();
    }
    
    @Test
    public void testJob() {
    
        JobScheduler scheduler = mock(JobScheduler.class);
        JobInfo pendingJob = mock(JobInfo.class)
        when(mContext.getSystemService(JOB_SCHEDULING_SERVICE)
        .thenReturn(scheduler);
        when(scheduler.getPendingJob(Job.POLLING_JOB_ID)).thenReturn(pendingJob);
    
        Abc.JobPerformer.job(mContext);
        
        verify(scheduler).getPendingJob(Job.POLLING_JOB_ID);
    }
    

    As you can see I do not need to mock Abc class.

    You are trying to call a method on a mocked class. You need a real instance of the class you are trying to test.