Search code examples
javamultithreadingjunitassert

For Junit issue: when test multiple thread


I use JDK ScheduledThreadPoolExecutor to do schdule job. I give simple code as below.

 class Job implements  Callable<Void>{
         public Long id;

        @Override
        public Void call() throws Exception {
            if (!isOk(id)) {
                return null;
            }

            _context.exe(id);
            return null;
        }


        void setId(Long id) {
            this.id = id;
        }
    }

Every time i add this job to schedule service:

public void schedule() {
    Job job = new Job();
    job.setId(1L);;
    _scheduledExecutor.schedule(job, 1000, TimeUnit.MILLISECONDS) ;
}

this job will delay call context's exe method. My Question: I want assert _context's exe method called or not? How can I do this?

What I do currently, I try to add log in call() method and verify UT by my eyes. PS: For this UT, I also try to mock _context's exe method, but job run in other thread, So I cannot assert it in currently thread. anyone have idea to help me write assert for this case?

Currently I do below way, but I still think there better solution for this, Just I don't known.

_context is instance of Context, I extend from this class.

public class UTContext extends Context {
public UTTestCase utTestCase ;

@Override
public void  exe(Long id) {
    utTestCase.setIsCall(true);  
}

public void setUtTestCase(UTTestCase utTestCase) {
    this.utTestCase = utTestCase;
}

}

Then I will assert isCall var in UT.

Is any one have good idea for this , pls give me answer. Thank you very much.


Solution

  • You are testing a piece of the middle of the call hierarchy, namely the thread creator/dispatcher code. That means you have to drive the code from the top and test either from the top or the bottom. There are several patterns for how you do that.

    Either you instrument the bottom (exe(id)) or you measure from the top. With the scheduling delay, measuring from the top becomes very difficult.

    Does exe() have side effects? Is that side effect testable from your test code? Can you infer the operation of one invocation of exe()? Can you infer the invocation of more than one? If the answer to any of these is "no", then you will have to go further.

    @RamonBoza has provided a good solution.

    You could also create a testable version of class Job, thus:

    class JobUT extends Job {
      @Override
      public Void call() throws Exception {
        Void result = super.call();
        // Report error if wrong return result
      }
    }
    

    (I know there are problems with the above code as Void is not being handled properly. I'm not in a position to refactor your code.)

    You may also achieve the same objective using Aspect Oriented Programming, where you intercept the call after it has completed and perform the same testing.