Robolectric 3.0 不适用于 AppCompat 21+

Robolectric 3.0 not working with AppCompat 21+

升级到 AppCompat 21 后,我们的很多 Robolectric 测试都失败了。看起来工具栏和 AppCompatDelegate

有问题

我尝试了 support-v4/appcompat 22.2.1 和 appcompat 官方示例中使用的版本:

https://github.com/robolectric/robolectric-samples/tree/master/android-appcompat-v7

    Android Studio 1.3 RC4, Android Gradle Plugin 1.2.3

    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    minSdkVersion 10
    targetSdkVersion 21

    compile 'com.android.support:support-v4:21.0.0'
    compile 'com.android.support:appcompat-v7:21.0.0'

    testCompile "org.robolectric:robolectric:3.0"
    testCompile 'org.robolectric:shadows-support-v4:3.0'

测试样本

    @Config(constants = BuildConfig.class)
    @RunWith(RobolectricGradleTestRunner.class)
    public class ActivateAccountActivityTest {

        @Test
        public void shouldRunActivateAccountActivity() throws Exception {
            // Given
            ActivateAccountActivity activateAccountActivity =
                    Robolectric.buildActivity(ActivateAccountActivity.class).create().start().get();

            // Then
            assertNotNull(activateAccountActivity.getFragment(ActivateAccountFragment.class));
        }
    }

测试失败,堆栈跟踪如下:

android.view.InflateException: XML file build/intermediates/res/app/debug/layout/abc_screen_toolbar.xml line #-1 (sorry, not yet implemented): Error inflating class android.support.v7.widget.Toolbar
        at android.view.LayoutInflater.createView(LayoutInflater.java:633)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:743)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
        at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:299)
        at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:246)
        at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
        at com.foo.myapp.Activities.ActivateAccountActivity.onCreate(ActivateAccountActivity.java:19)
        at android.app.Activity.performCreate(Activity.java:5933)
        at org.robolectric.util.ReflectionHelpers.callInstanceMethod(ReflectionHelpers.java:195)
        at org.robolectric.util.ActivityController.run(ActivityController.java:122)
        at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:304)
        at org.robolectric.shadows.CoreShadowsAdapter.runPaused(CoreShadowsAdapter.java:45)
        at org.robolectric.util.ActivityController.create(ActivityController.java:118)
        at org.robolectric.util.ActivityController.create(ActivityController.java:129)
        at com.foo.myapp.Activities.ActivateAccountActivityTest.shouldRunActivateAccountActivity(ActivateAccountActivityTest.java:40)
        at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:251)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58)
        at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
        at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:152)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
        at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
        at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
        at org.gradle.internal.concurrent.StoppableExecutorImpl.run(StoppableExecutorImpl.java:40)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:744)
    Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
        at android.view.LayoutInflater.$$robo$$createView(LayoutInflater.java:607)
        at android.view.LayoutInflater.createView(LayoutInflater.java)
        at android.view.LayoutInflater.$$robo$$createViewFromTag(LayoutInflater.java:743)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java)
        at android.view.LayoutInflater.$$robo$$rInflate(LayoutInflater.java:806)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java)
        at android.view.LayoutInflater.$$robo$$rInflate(LayoutInflater.java:809)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java)
        at android.view.LayoutInflater.$$robo$$inflate(LayoutInflater.java:504)
        at android.view.LayoutInflater.inflate(LayoutInflater.java)
        at android.view.LayoutInflater.$$robo$$inflate(LayoutInflater.java:414)
        at android.view.LayoutInflater.inflate(LayoutInflater.java)
        at android.view.LayoutInflater.$$robo$$inflate(LayoutInflater.java:365)
        at android.view.LayoutInflater.inflate(LayoutInflater.java)
        at android.support.v7.app.AppCompatDelegateImplV7.$$robo$$ensureSubDecor(AppCompatDelegateImplV7.java:299)
        at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java)
        at android.support.v7.app.AppCompatDelegateImplV7.$$robo$$setContentView(AppCompatDelegateImplV7.java:246)
        at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java)
        at android.support.v7.app.AppCompatActivity.$$robo$$setContentView(AppCompatActivity.java:106)
        at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java)
        at com.foo.myapp.Activities.ActivateAccountActivity.onCreate(ActivateAccountActivity.java:19)
        at android.app.Activity.$$robo$$performCreate(Activity.java:5933)
        at android.app.Activity.performCreate(Activity.java)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at org.robolectric.util.ReflectionHelpers.callInstanceMethod(ReflectionHelpers.java:195)
        at org.robolectric.util.ActivityController.run(ActivityController.java:122)
        at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:304)
        at org.robolectric.shadows.CoreShadowsAdapter.runPaused(CoreShadowsAdapter.java:45)
        at org.robolectric.util.ActivityController.create(ActivityController.java:118)
        at org.robolectric.util.ActivityController.create(ActivityController.java:129)
        at com.foo.myapp.Activities.ActivateAccountActivityTest.shouldRunActivateAccountActivity(ActivateAccountActivityTest.java:40)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:251)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58)
        at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
        at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:152)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
        at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
        at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:483)
        ... 8 more
    Caused by: java.lang.NoSuchMethodError: android.support.v4.content.ContextCompat.getDrawable(Landroid/content/Context;I)Landroid/graphics/drawable/Drawable;
        at android.support.v7.internal.widget.TintManager.getDrawable(TintManager.java:173)
        at android.support.v7.internal.widget.TintManager.getDrawable(TintManager.java:166)
        at android.support.v7.internal.widget.TintTypedArray.getDrawable(TintTypedArray.java:62)
        at android.support.v7.widget.Toolbar.__constructor__(Toolbar.java:249)
        at android.support.v7.widget.Toolbar.<init>(Toolbar.java)
        at android.view.LayoutInflater.createView(LayoutInflater.java:607)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:743)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
        at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:299)
        at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:246)
        at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
        at com.foo.myapp.Activities.ActivateAccountActivity.onCreate(ActivateAccountActivity.java:19)
        at android.app.Activity.performCreate(Activity.java:5933)
        at org.robolectric.util.ReflectionHelpers.callInstanceMethod(ReflectionHelpers.java:195)
        at org.robolectric.util.ActivityController.run(ActivityController.java:122)
        at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:304)
        at org.robolectric.shadows.CoreShadowsAdapter.runPaused(CoreShadowsAdapter.java:45)
        at org.robolectric.util.ActivityController.create(ActivityController.java:118)
        at org.robolectric.util.ActivityController.create(ActivityController.java:129)
        at com.foo.myapp.Activities.ActivateAccountActivityTest.shouldRunActivateAccountActivity(ActivateAccountActivityTest.java:40)
        at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:251)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
        at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58)
        at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
        at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:152)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
        at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
        at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
        ... 8 more

此问题是由依赖于 support-4v:19 的库引起的。 将以下内容添加到构建文件中解决了问题

    testCompile('com.example.foo') {
        exclude group: 'com.android.support', module: 'support-v4'
    }

我遇到了非常相似的问题,删除后我的问题得到了解决 "testCompile ('com.squareup:fest-android:1.0.8')" 来自我的 build.gradle.

我从 Robolectric migration document 中找到此信息并提取如下。希望对你有帮助。

DO NOT USE com.squareup:fest-android:1.0.8. If you have it in your testCompile be sure to remove it. There is a conflict between it and Robolectric which causes all Fragment/Activity related unit-tests to fail with NoSuchMethodError. If you have to use com.squareup:fest-android:1.0.8, then remove support-v4 from it: testCompile ('com.squareup:fest-android:1.0.8') { exclude module: 'support-v4' }