Search code examples
androidandroid-instrumentation

Run runTestOnUiThread from a different class


In our current framework we have a base class that extends ActivityInstrumentationTestCase2 | Android Developers. Typically when we write our test case classes we inherit this base class ( lets call it FooBase) and write our methods. As you can imagine this is getting really big and I would like to refactor it so that for each area of the feature we are testing it is in its own class so that we can reuse it. Hopefully my vague classes are accurate enough The goal is just being able to split the methods into different classes and call them from my testcase

 public class FooBase extends ActivityInstrumentionTestCase2 {
    @Override
 public void runTestOnUiThread(Runnable runnable) {
    try {
        super.runTestOnUiThread(runnable);
    } catch (InterruptedException e) {
        throw RuntimeInterruptedException.rethrow(e);
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Throwable e) {
        throw new RuntimeException(e);
    }
 }
 } 

and our test would be eg

public class TestFooBase extends FooBase{
      public void testfeature(){
               //execute a method that uses super.runTestOnUiThread()
      }

 }

How I attempted to refactor it

 public class FooHelper extends FooBase{
     public FooHelper(Activity activity){
         setActivity(activity)
     }
     public void sameMethod(){
         //moved the method in FooBase to this class that uses the runTestOnUiThread
     }

}

My new testcase would look something like this

public class TestFooBase extends FooBase{
      FooHelper fooHelper;
      public void setup(){
              fooHelper = new FooHelper(getActivity);
      }
      public void testfeature(){
               //execute a method that uses super.runTestOnUiThread()
               fooHelper.callthemethod()
      }

 }

When I execute this I get a null pointer on the super.runTestOnUIThread.


Solution

  • You can pass in the entire test class and set up a constructor for it.

    public class BaseTestCase {
        private Instrumentation instrumentation;
        private InstrumentationTestCase instrumentationTestCase;
    
        public BaseTestCase(InstrumentationTestCase testClass, Instrumentation instrumentation){
            this.instrumentationTestCase = testClass;
            this.instrumentation = instrumentation;
    }
    
        public Activity getCurrentActivity() {
            try {
                instrumentationTestCase.runTestOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                       //Code
                    }
                });
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return activity;
    
    }
    

    To use, you want to instantiate the BaseTestCase class on the setUp method

    public class ActivityTest extends ActivityInstrumentationTestCase2<TestActivity.class>{
        private BaseTestCase baseTestCase;
        @Override
        public void setUp() throws Exception { 
            super.setUp();
            getActivity();
            baseTestCase = new BaseTestCase(this, getInstrumentation());
        }
    }
    

    And to access the public methods in your BaseTestCase

    public void testRun(){
        baseTestCase.getCurrentActivity();
    }