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
editActivity that starts another activity.
class MyActivity extends Activity {
...
protected void startSomeActivity() {
startActivity(new Intent("start some activity");
}
...
}
Test
editExtend 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
editThis 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);
}
}
}
}