Search code examples
androidtestinggradleandroid-gradle-pluginandroid-instrumentation

Gradle build fails with "String Index out of range" when Android Tests Fail


I am experiencing a problem when trying to do instrumentation tests with Android. When one of the tests fails, the build fails, but doesn't state that the test failed. Instead I get FAILURE: Build failed with an exception. For the what went wrong section, I get String index out of range: -1.

In my real app, this is causing it to not generate a html report either, and the xml report is sporadically generated. I have put together a simple test case, but it is generating the report, but otherwise giving the same failure message.

To clarify, the test is designed to fail, but I would expect a A test has failed message instead of what looks like a different failure reason. I suspect that the failure is causing something else in the build lifecycle to go wrong leading to the message that I am seeing.

Here is the very simple test app

build.gradle

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.4.0-alpha7'
    }
}

apply plugin: 'com.android.application'

repositories {
    jcenter()
    mavenCentral()
}

dependencies {
    androidTestCompile "com.android.support.test.espresso:espresso-core:2.2.2"
    androidTestCompile "com.android.support.test.espresso:espresso-intents:2.2.2"
    androidTestCompile "com.android.support.test:runner:0.5"
}

android {
    compileSdkVersion 24
    buildToolsVersion '25.0.2'

    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8 
    }

    buildTypes {        
        release {
            minifyEnabled true
            proguardFile getDefaultProguardFile('proguard-android.txt')
        }
    }
}

src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.test.bad"
      android:versionCode="1"
      android:versionName="1">
    <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" />     
    <application android:label="bad">
        <activity android:name="BadTestActivity" android:label="bad">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

src/main/java/test/bad/BadTestActivity.java

package com.test.bad;

import android.app.Activity;
import android.os.Bundle;

public class BadTestActivity extends Activity {

    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

src/androidTest/java/com/test/bad/BadTest.java

package com.test.bad;

import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.fail;
import android.support.test.runner.AndroidJUnit4;

@RunWith(AndroidJUnit4.class)
public class BadTest {

    @Test
    public void failTest() {
        fail("This test just fails");
    }

}

When I run gradle connectedAndroidTest, I see

:connectedDebugAndroidTest

FAILURE: Build failed with an exception.

* What went wrong:
String index out of range: -1

* Try:
Run with --stacktrace option to get the stack trace.  Run with --info or --debug 
option to get more log output.

I would expect that to give some message about the build failing because of a failed test instead of something strange like that string index. In my real application (which also uses Kotlin and Mockito in tests) the report html is not always generated (there are many more tests, and I think that has something to do with the lack of a report).

Using --info or --debug doesn't seem to show anything useful, but using --stacktrace shows

* Exception is:
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
    at java.lang.String.substring(String.java:1967)
    at org.gradle.internal.logging.text.AbstractLineChoppingStyledTextOutput$StateContext.flushLineText(AbstractLineChoppingStyledTextOutput.java:115)
    at org.gradle.internal.logging.text.AbstractLineChoppingStyledTextOutput$2.execute(AbstractLineChoppingStyledTextOutput.java:167)
    at org.gradle.internal.logging.text.AbstractLineChoppingStyledTextOutput$2.execute(AbstractLineChoppingStyledTextOutput.java:160)
    at org.gradle.internal.logging.text.AbstractLineChoppingStyledTextOutput$1.execute(AbstractLineChoppingStyledTextOutput.java:146)
    at org.gradle.internal.logging.text.AbstractLineChoppingStyledTextOutput$1.execute(AbstractLineChoppingStyledTextOutput.java:131)
    at org.gradle.internal.logging.text.AbstractLineChoppingStyledTextOutput.doAppend(AbstractLineChoppingStyledTextOutput.java:41)
    at org.gradle.internal.logging.text.AbstractStyledTextOutput.text(AbstractStyledTextOutput.java:73)
    at org.gradle.internal.logging.text.AbstractStyledTextOutput.println(AbstractStyledTextOutput.java:68)
    at org.gradle.internal.logging.events.LogEvent.render(LogEvent.java:48)
    at org.gradle.internal.logging.console.StyledTextOutputBackedRenderer.onOutput(StyledTextOutputBackedRenderer.java:65)
    at org.gradle.internal.logging.sink.ProgressLogEventGenerator.doOutput(ProgressLogEventGenerator.java:72)
    at org.gradle.internal.logging.sink.ProgressLogEventGenerator.onOutput(ProgressLogEventGenerator.java:62)
    at org.gradle.internal.logging.console.BuildLogLevelFilterRenderer.onOutput(BuildLogLevelFilterRenderer.java:42)
    at org.gradle.internal.logging.sink.OutputEventRenderer$4.onOutput(OutputEventRenderer.java:265)
    at org.gradle.internal.logging.sink.OutputEventRenderer$LazyListener.onOutput(OutputEventRenderer.java:368)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:42)
    at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:230)
    at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:149)
    at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58)
    at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:324)
    at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:234)
    at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:140)
    at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:37)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy0.onOutput(Unknown Source)
    at org.gradle.internal.logging.sink.OutputEventRenderer.onOutput(OutputEventRenderer.java:334)
    at org.gradle.launcher.daemon.client.DaemonClient.monitorBuild(DaemonClient.java:216)
    at org.gradle.launcher.daemon.client.DaemonClient.executeBuild(DaemonClient.java:178)
    at org.gradle.launcher.daemon.client.DaemonClient.execute(DaemonClient.java:141)
    at org.gradle.launcher.daemon.client.DaemonClient.execute(DaemonClient.java:92)
    at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
    at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:173)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:287)
    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:260)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:33)
    at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:253)
    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:182)
    at org.gradle.launcher.Main.doAction(Main.java:33)
    at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
    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:498)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:60)
    at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:37)
    at org.gradle.launcher.GradleMain.main(GradleMain.java:23)

I am using Windows 7, with Gradle 4.0 (the problem exists with 3.5 as well) and Java 8. I am running my tests on a physical device - a Samsung Galaxy S6 running Nougat 7.0.

What is causing this error message? Is this what I should see?


Solution

  • It seems like this is a known issue with Gradle on Windows. There is a similar error description reported as issue 2077 and a fix issued (apparently this is caused by multiple \r characters). There is a note that this issue is to be fixed in Gradle 4.1.

    Update: 4.1 is now out, and this seems to have been fixed. The simple app above behaves as expected, and the real app that I had this problem with also behaves exactly as expected.