27

I'm new to Robolectric and instrumentation testing in general on Android. I followed along the guide for Robolectric for testing my first test. However I'm getting:

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

I searched for the error, but no solution is helping. I'm including everything that could cause this error.

Gradle:

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"
}

Manifest:

<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>

values/styles.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);
    }
}

Edit

Full Stacktrace

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)
timr
  • 6,668
  • 7
  • 47
  • 79

7 Answers7

33

I've just fixed same issue, and my workaround was this:

create a dummy Application and set theme inside onCreate():

public class TestApplication extends Application {

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

then inside the test you specify the application class in config:

@RunWith(RobolectricTestRunner.class)
@Config(application = TestApplication.class)
public class YourActivityTest {
    //tests
}
Szymon Chaber
  • 2,076
  • 16
  • 19
10

I faced that issue when I wanted to start a fragment that had appBar in its layout.

Below approach worked for me.

        launchFragmentInContainer<ProfileSettingsFragment>(themeResId = R.style.AppTheme).moveToState(Lifecycle.State.RESUMED)
Mieszko Koźma
  • 460
  • 4
  • 10
4

If there are components in the activity that use that context, another solution would be to get the Robolectric Context object, and set its theme to AppCompat. Here's the Kotlin code example in a unit test:

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


 
sorry_I_wont
  • 639
  • 1
  • 9
  • 16
3

Try this: Change your Android Manifest file to this:

<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>
KISHORE_ZE
  • 1,466
  • 3
  • 16
  • 26
1

It is a bug with Robotelectric, here is a workaround:

Android Lolipop Appcompat problems running with Robolectric

You may also try to upgrade to Robotelectric 3.0 to check if this is fixed.

Community
  • 1
  • 1
Derek Fung
  • 8,171
  • 1
  • 25
  • 28
  • then I believe it does not fix the problem in 3.0, you should try the workaround – Derek Fung Sep 02 '15 at 08:36
  • I'm sorry but the solution is not working aswell: android.content.res.Resources$NotFoundException: no such theme com.be.apppackage:themes/AppTheme – timr Sep 02 '15 at 08:50
1

In some cases it is necessary to set the theme manually.

@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)
    }
}

If you are going to test a customView/component that depends on a theme, remember to instantiate it only after assigning the theme to the activity

@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)
    }
}
Luiz Filipe Medeira
  • 1,142
  • 8
  • 13
0

You should use RobolectricGradleTestRunner instead.

import org.robolectric.RobolectricGradleTestRunner;

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

It solves my problem.

jiahao
  • 3,373
  • 2
  • 35
  • 36