【问题标题】:Robolectric: IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activityRobolectric:IllegalStateException:您需要在此活动中使用 Theme.AppCompat 主题(或后代)
【发布时间】:2015-11-27 14:00:23
【问题描述】:

我是 Robolectric 和 Android 上的一般仪器测试的新手。 我跟着guide for Robolectric 测试我的第一个测试。 但是我得到了:

java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.

我搜索了错误,但没有解决方案有帮助。我将所有可能导致此错误的内容都包括在内。

分级:

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt' //needed for source code generation
apply plugin: 'jacoco'
apply plugin: 'de.mobilej.unmock'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    testOptions {
        unitTests.returnDefaultValues = true
    }

    defaultConfig {
        applicationId "#######"
        minSdkVersion 15
        targetSdkVersion 22
        testHandleProfiling true
        testFunctionalTest true
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        debug{
            testCoverageEnabled false
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    lintOptions {
        abortOnError false
    }

    jacoco {
        version "0.7.1.201405082137"
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
        exclude 'META-INF/services/javax.annotation.processing.Processor'
        exclude 'LICENSE.txt'
    }

    jacoco {
        version "0.7.1.201405082137"
    }
}

def coverageSourceDirs = [
        '../app/src/main/java'
]

unMock {
    // URI to download the android-all.jar from. e.g. https://oss.sonatype.org/content/groups/public/org/robolectric/android-all/
    allAndroid =
            'https://oss.sonatype.org/content/groups/public/org/robolectric/android-all/4.3_r2-robolectric-0/android-all-4.3_r2-robolectric-0.jar'

    // classes to keep
    // matched by "startsWith" - you also need to include the dependencies manually
    // if you start with an "-" the class will match by "equals" (and it will additionally  match
    // inner classes of this class)
    keep = [
            "android.view.LayoutInflater",
            "android.support.v7.app.AppCompatActivity"
    ]
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile 'com.android.support:recyclerview-v7:22.0.+'
    compile 'com.android.support:cardview-v7:22.0.+'

    //Easy parsing JSON to POJO and vice versa
    compile 'com.google.code.gson:gson:2.3.1'

    //Photo's from URL to ImageView
    compile 'com.squareup.picasso:picasso:2.5.2'

    //REST API into an interface
    compile 'com.squareup.retrofit:retrofit:1.9.0'

    //Dependency Injection
    compile 'com.google.dagger:dagger:2.0.1'
    apt 'com.google.dagger:dagger-compiler:2.0.1'
    provided 'org.glassfish:javax.annotation:10.0-b28'
    compile 'com.jakewharton:butterknife:7.0.1'

    //Realm
    compile 'io.realm:realm-android:0.82.1'

    //RxAndroid (old version)
    compile 'io.reactivex:rxandroid:0.24.0'

    testCompile 'org.mockito:mockito-core:1.10.19'

    //Powermock
    testCompile ('org.powermock:powermock-api-mockito:1.6.2'){
        exclude group: 'org.mockito'
    }
    testCompile 'org.powermock:powermock-module-junit4:1.6.2'

    //Testing Framework
    //compile 'org.mockito:mockito-core:2.0.31-beta'
    testCompile 'junit:junit:4.12'

    //Robolectric
    testCompile "org.robolectric:robolectric:2.4"
}

清单:

<uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="22" />
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ui.MainActivity"
            android:label="@string/title">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
</application>

值/样式.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- colorPrimary is used for the default action bar background -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <!-- colorPrimaryDark is used for the status bar -->
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <!-- colorAccent is used as the default value for colorControlActivated,
     which is used to tint widgets -->
    <item name="colorAccent">@color/accent</item>

    <!-- set the application's background color -->
    <item name="android:colorBackground">@color/icons</item>
</style>

MainActivity.java

public class MainActivity extends AppCompatActivity{
    //implementation
}

MainActivityTest.java

@RunWith(RobolectricTestRunner.class)
public class MainActivityRoboTest {

    @Test
    public void test_onCreate_RecyclerViewShouldBeAvailable() throws Exception {
        MainActivity activity = Robolectric.setupActivity(MainActivity.class);
        RecyclerView r = (RecyclerView) activity.findViewById(R.id.rv);
    }
}

编辑

完整的堆栈跟踪

java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
    at android.support.v7.app.AppCompatDelegateImplBase.onCreate(AppCompatDelegateImplBase.java:124)
    at android.support.v7.app.AppCompatDelegateImplV7.onCreate(AppCompatDelegateImplV7.java:146)
    at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:59)
    at ui.MainActivity.onCreate(MainActivity.java:38)
    at android.app.Activity.performCreate(Activity.java:5008)
    at org.robolectric.internal.ReflectionHelpers$3.run(ReflectionHelpers.java:64)
    at org.robolectric.internal.ReflectionHelpers.traverseClassHierarchy(ReflectionHelpers.java:114)
    at org.robolectric.internal.ReflectionHelpers.callInstanceMethodReflectively(ReflectionHelpers.java:59)
    at org.robolectric.util.ActivityController$1.run(ActivityController.java:115)
    at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:268)
    at org.robolectric.util.ActivityController.create(ActivityController.java:111)
    at org.robolectric.util.ActivityController.create(ActivityController.java:122)
    at org.robolectric.util.ActivityController.setup(ActivityController.java:202)
    at org.robolectric.Robolectric.setupActivity(Robolectric.java:1388)
    at ui.MainActivityRoboTest.test_onCreate_RecyclerViewShouldBeAvailable(MainActivityRoboTest.java:21)
    at org.junit.runners.model.FrameworkMethod$1.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.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:236)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:158)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

【问题讨论】:

  • 你的代码实现的api版本是多少?
  • 查看更新的问题。

标签: java android functional-testing robolectric illegalstateexception


【解决方案1】:

试试这个: 将您的 Android 清单文件更改为:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme.AppCompat" >
    <activity
        android:name=".ui.MainActivity"
        android:label="@string/title">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

【讨论】:

  • 你的意思是 android:theme="@style/Theme.AppCompat" ?添加它但仍然无法正常工作同样的错误。
  • 我能看到完整的 logcat 吗?
  • 也可能是完整的build.gradle 文件
  • 尝试重启 Android Studio。 SDK Manger 是否配置正确?你删除了任何文件吗?
  • 此答案与 OP 描述的 Robolectric 问题无关。
【解决方案2】:

这是 Robotelectric 的一个错误,这里有一个解决方法:

Android Lolipop Appcompat problems running with Robolectric

您也可以尝试升级到 Robotelectric 3.0 以检查此问题是否已修复。

【讨论】:

  • 那么我认为它在 3.0 中无法解决问题,您应该尝试解决方法
  • 很抱歉,解决方案也不起作用:android.content.res.Resources$NotFoundException: no such theme com.be.apppackage:themes/AppTheme
【解决方案3】:

只需使用@RunWith(RobolectricTestRunner.class) 并快乐

@RunWith(RobolectricTestRunner.class)
public class MainActivityTest {

    @Test
    public void myTest() throws Exception {
        assertEquals(true, true);
    }
}

在此处查看更多信息:http://robolectric.org/getting-started/

【讨论】:

  • 请在投票前检查问题/答案日期和当前日期。问题是针对 Robolection v2.4 版本提出的,是这样的。
【解决方案4】:

您应该改用 RobolectricGradleTestRunner。

import org.robolectric.RobolectricGradleTestRunner;

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, manifest = Config.NONE)
public class MainActivityRoboTest {

它解决了我的问题。

【讨论】:

    【解决方案5】:

    我刚刚解决了同样的问题,我的解决方法是:

    创建一个虚拟应用程序并在 onCreate() 中设置主题:

    public class TestApplication extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            setTheme(R.style.AppTheme); //or just R.style.Theme_AppCompat
        }
    }
    

    然后在测试中你在 config 中指定应用程序类:

    @RunWith(RobolectricTestRunner.class)
    @Config(application = TestApplication.class)
    public class YourActivityTest {
        //tests
    }
    

    【讨论】:

    • 简洁高效,这解决了我的问题。
    • 工作吧。谢谢!
    【解决方案6】:

    当我想启动一个布局中包含 appBar 的片段时,我遇到了这个问题。

    以下方法对我有用。

            launchFragmentInContainer<ProfileSettingsFragment>(themeResId = R.style.AppTheme).moveToState(Lifecycle.State.RESUMED)
    

    【讨论】:

    • 谢谢!它对我有用!
    【解决方案7】:

    如果活动中存在使用该上下文的组件,另一种解决方案是获取 Robolectric 上下文对象,并将其主题设置为 AppCompat。这是单元测试中的 Kotlin 代码示例:

     val context: Context = ApplicationProvider.getApplicationContext()
     context.setTheme(R.style.your_theme_extending_AppCompat_Theme)
     // Use this context throughout the test.
    
    
     
    

    【讨论】:

    • 这正是我需要的解决方案。谢谢。
    【解决方案8】:

    在某些情况下需要手动设置主题。

    @RunWith(RobolectricTestRunner::class)
    class YourClassTest {
        private val activity: Activity = Robolectric.buildActivity(Activity::class.java).create().get()
    
        @Before
        fun setupTheme() {
            activity.setTheme(R.style.Theme_MaterialComponents_Light)
        }
    }
    

    如果您要测试依赖于主题的 customView/组件,请记住仅在将主题分配给活动后才实例化它

    @RunWith(RobolectricTestRunner::class)
    class YourClassTest {
        private val activity: Activity = Robolectric.buildActivity(Activity::class.java).create().get()
        private lateinit var yourCustomComponent: YourCustomComponent
    
        @Before
        fun setupTheme() {
            activity.setTheme(R.style.Theme_MaterialComponents_Light)
            yourCustomComponent = YourCustomComponent(activity)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-03-15
      • 2016-07-04
      • 2016-05-16
      • 1970-01-01
      • 2018-06-05
      相关资源
      最近更新 更多