Create a gist now

Instantly share code, notes, and snippets.

CustomTestRunner (Robolectric 2.x) and Crashlytics shadow class
package com.example;
import com.example.shadows.ShadowCrashlytics;
import org.junit.runners.model.InitializationError;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.bytecode.ClassInfo;
import org.robolectric.bytecode.Setup;
import org.robolectric.bytecode.ShadowMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Custom unit test runner. Enables custom shadows for testing third party library integrations.
* <p />
* <strong>Adding a Custom Shadow</strong>
* <ol>
* <li>Create a new custom shadow class using instructions outlined here:
* http://robolectric.blogspot.com/2011/01/how-to-create-your-own-shadow-classes.html</li>
* <li>Map the shadow class to the original using
* {@link org.robolectric.annotation.Implements}.</li>
* <li>Customize behavior of the shadow using
* {@link org.robolectric.annotation.Implementation}.</li>
* <li>Add the original class name to the {@link #CUSTOM_SHADOW_TARGETS} list.</li>
* <li>Bind the shadow class by calling {@link ShadowMap.Builder#addShadowClass(Class)} in
* {@link #createShadowMap()}.</li>
* <li>Be sure to use {@code @RunWith(CustomTestRunner.class)} at the top of your tests.</li>
* </ol>
*/
public class CustomTestRunner extends RobolectricTestRunner {
/**
* List of fully qualified class names backed by custom shadows in the test harness.
*/
private static final List<String> CUSTOM_SHADOW_TARGETS =
Collections.unmodifiableList(Arrays.asList(
"com.crashlytics.android.Crashlytics"
));
public CustomTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
/**
* Adds custom shadow classes to Robolectric shadow map.
*/
@Override
protected ShadowMap createShadowMap() {
return super.createShadowMap()
.newBuilder()
.addShadowClass(ShadowCrashlytics.class)
.build();
}
/**
* Replaces Robolectric {@link Setup} with {@link CustomSetup} subclass.
*/
@Override
public Setup createSetup() {
return new CustomSetup();
}
/**
* Modified Robolectric {@link Setup} that instruments third party classes with custom shadows.
*/
public class CustomSetup extends Setup {
@Override
public boolean shouldInstrument(ClassInfo classInfo) {
return CUSTOM_SHADOW_TARGETS.contains(classInfo.getName())
|| super.shouldInstrument(classInfo);
}
}
}
package com.example.shadows;
import android.content.Context;
import com.crashlytics.android.Crashlytics;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
/**
* Custom shadow implementation for {@link com.crashlytics.android.Crashlytics}.
*/
@SuppressWarnings("unused")
@Implements(Crashlytics.class)
public class ShadowCrashlytics {
private static Context context = null;
private static String userIdentifier = null;
@Implementation
public static void start(Context context) {
ShadowCrashlytics.context = context;
}
@Implementation
public static void setUserIdentifier(String identifier) {
userIdentifier = identifier;
}
public static Context getContext() {
return context;
}
public static String getUserIdentifier() {
return userIdentifier;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment