Tuesday, July 30, 2013

Junit multiple users functionalities with TestRule interface

Recently I was trying to do some performance testing integrated with build. There are some use cases that I want to simulate multi users(Threads) behavior inside my junit test cases to have multiple threads executing the tests concurrently.

Then TestRule, a built in Junit interface which brought my attention, is easy and powerful to customize your test code behaviors.

TestRule
As I understand, the TestRule is an interface which developer can inject into test classes, which is similar to the aspectj Around point cut.

The code below implements TestRule and return an inner class as CustomStatement that injects some code before and after the testing code (base.evaluate())

public class SimpleTestRule implements TestRule{
 
 public Statement apply(Statement base, Description description) {
  return new CustomStatement(base);
 }
 
 private class CustomStatement extends Statement{
  private Statement base;
  
  public CustomStatement(Statement base) {
   this.base = base;
  }

  @Override
  public void evaluate() throws Throwable {
   //Before test execution
   System.out.println("Before Test Running");
   //Test execution
   base.evaluate();
   //After test execution
   System.out.println("After Test Running");
   
  }
  
 }
}

Use the above Custom Test Rule
public class SimpleTestRuleTest {
 
 @Rule
 public TestRule rule = new SimpleTestRule();
 
 @Test
 public void test(){
  System.out.println("My test is running");
 }
}

Code execution Result:

Before Test Running
My test is running
After Test Running


Multiple User TestRule

After understanding the above simple test rule, we can start create a more complicate rule to support multiple threading of tests.

The following code wrapped the test execution code (base.evaluate()) into an independent thread.

public class MultiUserTestRule implements TestRule{
 
 private final int numOfUsers;
 private final ExecutorService executor;
 
 public MultiUserTestRule(int poolSize, int numOfUsers){
  this.numOfUsers = numOfUsers;
  executor = Executors.newFixedThreadPool(poolSize);
 }

 public Statement apply(Statement base, Description description) {
  return new CustomStatement(base);
 }
 
 private class CustomStatement extends Statement{
  
  private Statement base;
  
  public CustomStatement(Statement base) {
   this.base = base;
  }

  @Override
  public void evaluate() throws Throwable {
   for(int i=0; i< numOfUsers; i++){
    executor.execute(new Thread(new Runnable() {
     
     public void run() {
      try {
       base.evaluate();
      } catch (Throwable e) {
       throw new IllegalArgumentException(e);
      }
     }
    }));
   }
  }
  
 }

}
Use the above test Rule
public class MultiUserTestRuleTest {
 /**
  * The thread pool size is 10
  * There are 5 users run the tests
  */
 @Rule
 public TestRule rule = new MultiUserTestRule(10, 5);
 
 @Test
 public void test(){
  System.out.println(Thread.currentThread().getName() + " is running the test");
 }
}
The above test case is trying to print out each current thread name for demo purpose.
The result is:
pool-1-thread-1 is running the test
pool-1-thread-4 is running the test
pool-1-thread-5 is running the test
pool-1-thread-2 is running the test
pool-1-thread-3 is running the test

All the above code can be found here: https://github.com/datianshi/multiuser-junit

No comments:

Post a Comment