7

I want to use multiple external resources in my test class, but I have a problem with ordering of external resources.

Here is code snippet :

public class TestPigExternalResource {

     // hadoop external resource, this should start first
     @Rule
     public HadoopSingleNodeCluster cluster = new HadoopSingleNodeCluster();

     // pig external resourcem, this should wait until hadoop external resource starts
     @Rule
     public  PigExternalResource pigExternalResource = new PigExternalResource(); 

     ...  
}

The problem is it tries to start pig before hadoop started, therefore I could not connect local hadoop single node cluster.

Is there any way to order rules of junit?

thanks

Salih Kardan
  • 579
  • 1
  • 6
  • 16
  • Is `HadoopSingleNodeCluster` class publicly available? As i use `org.apache.hadoop.mapred.ClusterMapReduceTestCase`, but it's not that stable. – nefo_x Jun 03 '14 at 11:59
  • @nefo_x **HadoopSingleNodeCluster** is my own class, not available in hadoop distribution. – Salih Kardan Jun 03 '14 at 13:10
  • is it based on some existing codebase? I try to use cluster mapreduce testcase, but it launches external JVMs and that's a bit hard for debugging in some cases. – nefo_x Jun 04 '14 at 16:17

3 Answers3

11

You can use RuleChain.

@Rule
public TestRule chain= RuleChain.outerRule(new HadoopSingleNodeCluster())
                           .around(new PigExternalResource());
Stefan Birkner
  • 24,059
  • 12
  • 57
  • 72
1

Why don't you wrap these two ExternalResources in your own ExternalResource that calls the before and after methods in the order you require from within the new resource's before and after methods.

Example:

public class MyResource extends ExternalResource{
     private final List<ExternalResource> beforeResources;
     private final List<ExternalResource> afterResources;

     public MyResource(List<ExternalResource> beforeResources,
          List<ExternalResource> beforeResources){
     }

      public void before(){
          for (ExternalResource er : beforeResources)
               er.before();
      }

      public void after(){
          for (ExternalResource er : afterResources)
               er.after();
      }
}


public class TestPigExternalResource {

 // hadoop external resource, this should start first
 public HadoopSingleNodeCluster cluster = new HadoopSingleNodeCluster();

 // pig external resourcem, this should wait until hadoop external resource starts
 public  PigExternalResource pigExternalResource = new PigExternalResource(); 

  @Rule
  public MyResource myResource = new MyResource(
          newArrayList(cluster, pigExternalResource),
          newArrayList(cluster, pigExternalResource));
 ...  
}
John B
  • 32,493
  • 6
  • 77
  • 98
  • Thanks but I guess using @Rule annotation in before and after method is not allowed. – Salih Kardan Oct 04 '13 at 11:12
  • See example added to post. The other resources would no longer be marked as rules since they would be included in the wrapping rule. – John B Oct 04 '13 at 11:36
1

There's a new order attribute in @Rule and @ClassRule as of JUnit 4.13-beta-1.

See @Rule code :

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface Rule {

    int DEFAULT_ORDER = -1;

    /**
     * Specifies the order in which rules are applied. The rules with a higher value are inner.
     *
     * @since 4.13
     */
    int order() default DEFAULT_ORDER;

}

See also this PR for reference : PR-1445.

Guillaume Husta
  • 4,049
  • 33
  • 40