@Test
  public void onStop_calledOnMainThread() throws Exception {
    final SettableFuture<Looper> looperFuture = SettableFuture.create();
    final JobService service =
        new JobService() {
          @Override
          public boolean onStartJob(@NonNull JobParameters job) {
            return true; // more work to do
          }

          @Override
          public boolean onStopJob(@NonNull JobParameters job) {
            looperFuture.set(Looper.myLooper());
            return false;
          }
        };

    Job jobSpec =
        TestUtil.getBuilderWithNoopValidator()
            .setTag("tag")
            .setService(service.getClass())
            .setTrigger(Trigger.NOW)
            .build();

    final Bundle jobSpecData = getJobCoder().encode(jobSpec, new Bundle());
    IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, noopCallback);

    // call stopJob on a background thread and wait for it
    Executors.newSingleThreadExecutor()
        .submit(
            new Runnable() {
              @Override
              public void run() {
                try {
                  IRemoteJobService.Stub.asInterface(service.onBind(null)).stop(jobSpecData, true);
                } catch (RemoteException e) {
                  throw new AssertionError("calling stop on binder unexpectedly failed", e);
                }
              }
            })
        .get(1, TimeUnit.SECONDS);

    flush(service);

    assertEquals(
        "onStopJob was not called on main thread",
        Looper.getMainLooper(),
        looperFuture.get(1, TimeUnit.SECONDS));
  }
Tests for the {@link JobService} class.
jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobServiceTest.java