Android/Testing/Unit Testing/Monitor supermethods

      Some monitoring behaviour is common: Activities can start other activities, for instance, and testing those calls involves recording the intents issued during the test. Robolectric offers this behaviour with its ShadowContextWrapper.getNextActivity, but the following may be a more useful strategy in certain circumstances.

      Code under test

      Activity that starts another activity.

      class MyActivity extends Activity {
        ...
        protected void startSomeActivity() {
           startActivity(new Intent("start some activity");
        }
        ...
      }
      

      Test

      Extend the activity under test, overriding the startActivity() method:

      class MyActivityTest {
       class MonitoredMyActivity extends MyActivity implements MonitoringForStartActivity {
           List<Intent> startActivityCalls = new ArrayList<Intent>();
       
           @Override
           List<Intent> startActivityCalls() {
               return this.startActivityCalls;
           }
       
           @Override
           boolean startActivity(Intent i) {
               this.startActivityCalls.add(i);
           }
       }
       
       MonitoredMyActivity activity = new MonitoredMyActivity();
       
       @Test
       public void _TestActivityStarted() {
         activity.startSomeActivity();  
         assertThat(monitoredActivity, hasStartedActivity(intentMatching("start some activity")));
       }
      }
      

      Misc

      This is a wrapping-up of being able to monitor an activity:

      import android.content.Intent;
      import org.hamcrest.Description;
      import org.hamcrest.Matcher;
      import org.hamcrest.TypeSafeDiagnosingMatcher;
       
      import java.util.Iterator;
      import java.util.List;
       
      /**
       * Matcher with a mix-in interface, to monitor 'startActivity()' calls.
       *
       * Boilerplate:
       *
       * class MonitoredMyActivity extends MyActivity implements MonitoringForStartActivity {
       *     List<Intent> startActivityCalls = new ArrayList<Intent>();
       *
       *     @Override
       *     List<Intent> startActivityCalls() {
       *         return this.startActivityCalls;
       *     }
       *
       *     @Override
       *     boolean startActivity(Intent i) {
       *         this.startActivityCalls.add(i);
       *     }
       * }
       *
       * assertThat(monitoredActivity, hasStartedActivity(sameInstance(someIntent)));
       */
       
      public class MonitoringForStartActivityTypeSafeDiagnosingMatcher extends TypeSafeDiagnosingMatcher<MonitoringForStartActivityTypeSafeDiagnosingMatcher.MonitoringForStartActivity>
      {
              public interface MonitoringForStartActivity
              {
                      List<Intent> didCallStartActivity();
              }
       
              public static Matcher<MonitoringForStartActivity> hasNeverStartedActivity()
              {
                      return new MonitoringForStartActivityTypeSafeDiagnosingMatcher();
              }
       
              public static Matcher<MonitoringForStartActivity> hasStartedActivity(final Matcher<Intent> matcher)
              {
                      return new MonitoringForStartActivityTypeSafeDiagnosingMatcher(matcher);
              }
       
              public MonitoringForStartActivityTypeSafeDiagnosingMatcher(Matcher<Intent> ... matchers)
              {
                      this.matchers = matchers;
              }
       
              private final Matcher<Intent>[] matchers;
       
              @Override
              protected boolean matchesSafely(MonitoringForStartActivityTypeSafeDiagnosingMatcher.MonitoringForStartActivity monitoredTestActivity, Description description)
              {
                      final List<Intent> intents = monitoredTestActivity.startActivityCalls();
                      description.appendText(" startActivity was called " + intents.size() + " times");
                      if (intents.size() == 0)
                      {
                              description.appendText(" never");
                      }
                      else
                      {
                              description.appendText(" with");
                              for (Intent intent : intents)
                              {
                                      description.appendText(": " + intent);
                              }
                      }
                      if (intents.size() != matchers.length)
                      {
                              return false;
                      }
                      boolean matchesAll = true;
                      Iterator<Intent> eachIntent = intents.iterator();
                      for (Matcher<Intent> matcher : matchers)
                      {
                              matchesAll = matchesAll && eachIntent.hasNext() && matcher.matches(eachIntent.next());
                      }
                      return matchesAll;
              }
       
              @Override
              public void describeTo(Description description)
              {
                      if (matchers.length == 0)
                      {
                              description.appendText(" never calls startActivity");
                      }
                      else
                      {
                              description.appendText(" calls startActivity with ");
                              for (Matcher<Intent> matcher : matchers)
                              {
                                      description.appendDescriptionOf(matcher);
                              }
                      }
              }
      }
      
      Last modified on 26 June 2012, at 21:11