Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Robolectric: how to test a SherlockActivity

I'm trying to run tests on an Activity which extends SherlockActivity. I read everything I could find about the solutions for testing activities with ActionBarSherlock and also tried following https://github.com/passy/absshadow-sample

this is what I'm currently doing:

custom test runner:

public class CustomTestRunner extends RobolectricTestRunner {
    private static final int SDK_INT = Build.VERSION.SDK_INT;

    public CustomTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
        addClassOrPackageToInstrument("com.actionbarsherlock.app.SherlockActivity");
    }

    @Override
    protected void bindShadowClasses() {
        super.bindShadowClasses();
        Robolectric.bindShadowClass(ShadowSherlockActivity.class);
    }

    @Override
    public void beforeTest(final Method method) {
        final int targetSdkVersion = robolectricConfig.getSdkVersion();
        setStaticValue(Build.VERSION.class, "SDK_INT", targetSdkVersion);
    }

    @Override
    public void afterTest(final Method method) {
        resetStaticState();
    }

    @Override
    public void resetStaticState() {
        setStaticValue(Build.VERSION.class, "SDK_INT", SDK_INT);
    }
}

shadow SherlockActivity:

@Implements(SherlockActivity.class)
public class ShadowSherlockActivity extends ShadowActivity {

    @Implementation
    public void setContentView(int layoutResID) {
        super.setContentView(layoutResID);    // TODO Auto-generated method stub
    }

    @Implementation
    public ActionBar getSupportActionBar() {
        return new ActionBar() {
            // removed for readability
        };
    }
}

for some reason its aways failing with this:

WARNING: you probably should have called setContentView() first
java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1342)
    at     com.xtremelabs.robolectric.shadows.ShadowActivity.findViewById(ShadowActivity.java:183)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.xtremelabs.robolectric.bytecode.ShadowWrangler.methodInvoked(ShadowWrangler.java:99)
    at com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(RobolectricInternals.java:144)
    at android.app.Activity.findViewById(Activity.java)
    at com.dgti.ds.activities.ChooseLocationActivity.findViews(ChooseLocationActivity.java:44)
    at com.dgti.ds.activities.ChooseLocationActivity.onCreate(ChooseLocationActivity.java:34)
    at com.dgti.ds.activities.ChooseLocationActivityTests.shouldGetGoogleAPIKeyIfNull(ChooseLocationActivityTests.java:81)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at com.xtremelabs.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:288)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

my activity does call setContentView first, before any findViewById.

the weird part is that no matter what I do in the shadow implementation of setContentView, nothing seems to happen (for example, throwing a NullPojnterException). my shadow does get registered, as if I try to override the implementation of onCreate and throw the exception there, it does work.

what am I missing here ?

like image 706
Gal Ben-Haim Avatar asked Nov 04 '12 09:11

Gal Ben-Haim


People also ask

Is Robolectric deprecated?

Robolectric is intended to be fully compatible with Android's official testing libraries since version 4.0. As such we encourage you to try these new APIs and provide feedback. At some point the Robolectric equivalents will be deprecated and removed.

What are shadows in Robolectric?

Robolectric has an important concept called shadows. Shadows are classes that modify or extend the behavior of classes in the Android SDK. Most of the Android core views are built with shadow classes to avoid needing the device or an emulator to run.

What is AndroidX test?

AndroidX Test is a collection of Jetpack libraries that lets you run tests against Android apps. It also provides a series of tools to help you write these tests. For example, AndroidX Test provides JUnit4 rules to start activities and interact with them in JUnit4 tests.


1 Answers

apparently changing the Java SDK in Intellij's project settings to Oracle instead of OpenJDK fixed this issue for me.

like image 64
Gal Ben-Haim Avatar answered Sep 17 '22 14:09

Gal Ben-Haim