9

I recently updated a few libraries in my gradle file, and as a result, some (but not all) of my unit tests fail when I run them in the console by "./gradlew clean test". However, all my tests pass successfully when I run them inside Android Studio.

Here is a snapshot of my gradle file:

apply plugin: 'com.android.application'
apply plugin: 'android-aspectj'
apply plugin: 'android'
apply plugin: 'idea'
apply plugin: 'org.robolectric'


android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        minSdkVersion 17
        targetSdkVersion 19    
    }

    signingConfigs {
        release {
            ...
        }
    }

    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java']
            res.srcDirs = ['src/main/res']
            assets.srcDirs = ['src/main/assets']
        }
        test.setRoot("src/test")
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            signingConfig signingConfigs.release
        }
        debug {
            ...
        }
    }

    lintOptions {
        abortOnError false
    }

    testOptions {
        unitTests.returnDefaultValues = true
    }

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

buildscript {
    repositories {
        mavenCentral()
        mavenLocal()
        jcenter()
        maven {
            url 'https://oss.sonatype.org/content/repositories/snapshots/'
        }
    }

    dependencies {
        classpath 'com.github.dcendents:android-maven-plugin:1.0'
        classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'
        classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1'
    }
}

dependencies {
    compile 'com.android.support:support-v4:22.1.1'
    compile 'com.android.support:appcompat-v7:22.1.1'
    compile 'com.google.android.gms:play-services:7.3.0'
    compile 'org.apache.httpcomponents:httpcore:4.3'
    compile 'org.apache.httpcomponents:httpmime:4.3.5'
    compile 'org.apache.httpcomponents:httpclient:4.3.5'
    compile 'com.google.code.gson:gson:2.3'
    testCompile 'org.hamcrest:hamcrest-integration:1.3'
    testCompile 'org.hamcrest:hamcrest-core:1.3'
    testCompile 'org.hamcrest:hamcrest-library:1.3'
    testCompile 'com.squareup:fest-android:1.0.+'
    testCompile 'org.mockito:mockito-core:1.+'
    testCompile 'org.jmockit:jmockit:1.8'
    testCompile('junit:junit:4.12') {
        exclude module: 'hamcrest-core'
    }
    testCompile('org.robolectric:robolectric:2.4') {
        exclude module: 'classworlds'
        exclude module: 'commons-logging'
        exclude module: 'httpclient'
        exclude module: 'maven-artifact'
        exclude module: 'maven-artifact-manager'
        exclude module: 'maven-error-diagnostics'
        exclude module: 'maven-model'
        exclude module: 'maven-project'
        exclude module: 'maven-settings'
        exclude module: 'nekohtml'
        exclude module: 'plexus-container-default'
        exclude module: 'plexus-interpolation'
        exclude module: 'plexus-utils'
        exclude module: 'wagon-file'
        exclude module: 'wagon-http-lightweight'
        exclude module: 'wagon-http-shared'
        exclude module: 'wagon-provider-api'
    }
}

idea {
    module {
        testOutputDir = file("build/test-classes")

        testSourceDirs += file('test/')
    }
}

The error I am getting is this:

java.lang.NullPointerException
    at mockit.internal.mockups.MockStates.getMockState(MockStates.java:99)
    at mockit.internal.mockups.MockStates.updateMockState(MockStates.java:92)
    at mockit.internal.state.TestRun.updateMockState(TestRun.java:138)
    at org.junit.runners.model.FrameworkMethod.validatePublicVoidNoArg(FrameworkMethod.java)
    at org.junit.runners.ParentRunner.validatePublicVoidNoArgMethods(ParentRunner.java:155)
    at org.junit.runners.BlockJUnit4ClassRunner.validateTestMethods(BlockJUnit4ClassRunner.java:208)
    at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:188)
    at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:128)
    at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)

My custom RobolectricGradleTestRunner is:

public class RobolectricGradleTestRunner extends RobolectricTestRunner {
    private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC = 18;

    public RobolectricGradleTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override
    protected AndroidManifest getAppManifest(Config config) {
        String dir = System.getProperty("user.dir");
        String manifestProperty = dir + "/build/intermediates/manifests/full/debug/AndroidManifest.xml";
        String resProperty = dir + "/build/intermediates/res/debug";
        return new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty)) {
            @Override
            public int getTargetSdkVersion() {
                return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC;
            }
        };
    }
}

And this is one of my tests that is failing:

@RunWith(RobolectricGradleTestRunner.class)
public class AboutActivityTest {
    private AboutActivity activity;

    @Before
    public void initialize() {
        activity = Robolectric.buildActivity(AboutActivity.class).create().start().get();
    }


    @Test
    public void testAboutPage() {
        assertNotNull("AboutActivity is null", activity);
        Fragment fragment = activity.getFragmentManager().findFragmentByTag(AboutFragment.FRAGMENT_TAG);
        assertNotNull("fragment is null", fragment);
        Button button = (Button) fragment.getView().findViewById(R.id.buttonTour);
        assertNotNull("Tour button is null", button);
        ShadowActivity shadowHome = Robolectric.shadowOf(activity);
        button.performClick();
        assertThat(shadowHome.peekNextStartedActivityForResult().intent.getComponent(), equalTo(new ComponentName(activity, TourActivity.class)));
    }
}

Based on what I see, it seems jmockit is having some problem to initialize. But I am not sure what it is. Any help is greatly appreciated.

happyhuman
  • 1,541
  • 1
  • 16
  • 30
  • Make sure you use `Robolectric` 3.0+, it comes with `RobolectricGradleTestRunner`, delete yours. You no longer need the plugin as well `apply plugin: 'org.robolectric'`. – Jared Burrows May 12 '15 at 19:50
  • Thanks for your response. I actually tried Robolectric 3.0 and it had its own problems, mainly backward incompatibility. So, my tests were broken for another reason. I believe my problem has nothing to do with the version of the Robolectric or my custom RobolectricGradleTestRunner since the tests run fine in Android Studio, but not in the console. – happyhuman May 13 '15 at 03:25
  • Honestly, I would go to Robolectric 3.0, look at the wiki on how to upgrade. It solved all my problems. Just follow my steps, I have setup Robolectric many, many times. – Jared Burrows May 13 '15 at 07:00
  • After a lot of code change, I was able to upgrade to Robolectric 3.0-rc2. Unfortunately the problem persists. My best guess is that it has something to do with the ordering of jar files in the classpath and that jmockit should appear before junit, due to this warning message that I see: "WARNING: JMockit was initialized on demand, which may cause certain tests to fail; please check the documentation for better ways to get it initialized." – happyhuman Jun 03 '15 at 18:55
  • Remember, Robolectric is not really meant to work nicely with other "mocking" frameworks as it does a lot of mocking for "stubbed" implementations that come with the android.jar. Do you have your project on Github? – Jared Burrows Jun 04 '15 at 01:57
  • That may be. But it does not explain why the tests are successfully pass in Android Studio, and they mostly fail when I run them in the console. I am looking into other mocking options, but Mockito by itself has limitations (e.g. no mocking of static methods), and PowerMockito is not easy to use either. So, still stuck. :) – happyhuman Jun 06 '15 at 00:01
  • You hold yourself back and give yourself no real options. Robolectric 3.0 + Mockito will work for you just fine. – Jared Burrows Jun 06 '15 at 02:53

0 Answers0