ClassCastException: NoClassDefFoundError cannot be cast to RuntimeException
Asked Answered
B

3

18

I am working on upgrading my codebase to Gradle 2.2 and Android Studio 1.0. I am currently trying to get Robolectric 2.4 working, but I am experiencing a strange issue when I try and run Unit Tests. The issue occurs only after a gradle clean; running the test suite multiple times will produce passing tests (as expected). When I run the tests after a clean, I get the following error:

java.lang.ClassCastException: java.lang.NoClassDefFoundError cannot be cast to java.lang.RuntimeException

I have traced the error back to this call:

Activity activity = Robolectric.setupActivity(MainActivity.class);

I experience this error whether I use the Robolectric gradle plugin (org.robolectric:robolectric-gradle-plugin:0.14.0) or the JC and K Android unit test plugin (com.github.jcandksolutions.gradle:android-unit-test:2.1.1).

I found this issue referenced on the Robolectric Github, but it doesn't look like it has been addressed yet: https://github.com/robolectric/robolectric/issues/1385

This issue is also referenced in the android studio unit test plugin, under 'Trouble Shooting': https://github.com/evant/android-studio-unit-test-plugin

My current sample code is here: https://github.com/KioKrofovitch/robolectric-upgrade-test

I have been able to run the api-android-16 project on the Robolectric samples without seeing this issue, though api-android-19 and api-android-21 projects fail for other reasons. I cannot see what they are doing differently such that they do not get this failure. https://github.com/robolectric/robolectric-samples

Has anyone found a workaround to this? Running the tests twice is not a good workaround for CI tools like Jenkins or Travis.

EDIT: Embedding code samples

My top level build.gradle where I add the JC and K Unit test library:

buildscript {
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.0.0'
        classpath 'com.github.jcandksolutions.gradle:android-unit-test:2.1.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

My project level build.gradle, where I add in robolectric:

apply plugin: 'com.android.application'

repositories {
    mavenCentral()
}

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.example.robolectrictest"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }

        androidTest {
            setRoot('src/androidTest')
        }
    }
}

// Must be after Android plugin
apply plugin: 'android-unit-test'

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'

    //androidTestCompile 'junit:junit:4.10'
    //androidTestCompile 'org.robolectric:robolectric:2.4'

    // Testing frameworks
    testCompile 'junit:junit:4.10'
    testCompile 'org.robolectric:robolectric:2.4'
}

My very basic Activity, everything has been left as the template creates it:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

My dummy test, where I can't get to my assert due to the setupActivity() method error:

@Config(emulateSdk = 18)
@RunWith(RobolectricTestRunner.class)

public class ApplicationTest {

    @org.junit.Test
    public void testDummy() throws Exception {

        Activity activity = Robolectric.setupActivity(MainActivity.class);

        assertTrue(true);
    }

}

EDIT #2: To run the tests I invoke the following commands from the top level directory of my project:

./gradlew clean
./gradlew test

I have also tried running the tests outside the gradle wrapper, and get the same results

gradle clean
gradle test
Bukavu answered 19/12, 2014 at 21:32 Comment(6)
Can you actually paste the relevant code into this question? I have no idea which files out of your github project I'm supposed to be looking at.Gascony
Sure, thanks! I've added the most relevant code snippetsBukavu
Right. Definitely a gradle issue, and I'm afraid I know very little about gradle, so this is beyond my ability to help you with. What I've done though, is substitute the gradle tag for the android tag in the question, in the hope that some gradle expert will come along and find your question. Sorry that I couldn't be more help.Gascony
Can you show the gradle command you are using to run the test? Thanks.Blueness
Thanks, AndroidGuy. I've updated my question accordingly.Bukavu
I also run into this issue when configuring the tests manually in a separate module (not using a plugin).Concoction
B
13

This was confirmed as an issue with Robolectric 2.4 (Issue #1385). The issue has been closed by Erich Douglass today, with the following comment:

We are working on appcompat support for 3.0. Until then, there's not much you can do.

https://github.com/robolectric/robolectric/issues/1385

So until 3.0 is released, I will be using the following workaround:

./gradlew clean
./gradlew assemble
./gradlew test

Once the assemble has run, it has created all the items that Robolectric apparently needs. Then you can run your tests successfully. This solution is better than just running ./gradlew build or ./gradlew test twice, because it can be implemented both locally as well as on a CI tool like Travis or Jenkins. The syntax for running multiple Gradle tasks in Jenkins is leaving a single space between each task:

assemble test
Bukavu answered 31/12, 2014 at 20:39 Comment(1)
Are there any other workarounds? This one doesn't work for me.Contrapositive
E
1

After upgrading Android Gradle Plugin to 1.1.3 from 1.1.0 the exception went away. Can anyobody else confirm this? I'm using the setup described here: http://nenick-android.blogspot.de/2015/02/android-studio-110-beta-4-and.html

Ending answered 27/3, 2015 at 8:7 Comment(0)
K
0

My issue is resolved. I updated my robolectirc to 2.4 and min SDK to 19 and android support to com.android.support:support-v13:19.1.0. And also did changes to iml files for the same.

Thanks For Your guidance and response

Venkatraman

Kenyon answered 7/1, 2015 at 7:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.