Last active
May 3, 2023 07:51
-
-
Save pyricau/970b95a4757a99b26562fd95e146f38f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example | |
import android.app.Instrumentation | |
import android.os.Bundle | |
import android.util.Log | |
import androidx.test.internal.runner.listener.InstrumentationResultPrinter | |
import androidx.test.platform.app.InstrumentationRegistry | |
import org.junit.runner.Description | |
import org.junit.runner.notification.RunListener | |
/** | |
* A JUnit [RunListener] that installs a default [Thread.UncaughtExceptionHandler] to detect crashes | |
* in instrumentation tests and report a failure status to [Instrumentation], before letting the | |
* default crash handling continue (which will terminate the process). | |
* | |
* All you need to do is add the following to the defaultConfig of build.gradle: | |
* | |
* ``` | |
* testInstrumentationRunnerArgument "listener", | |
* "com.example.CrashingRunListener" | |
* ``` | |
* | |
* Then you can run instrumentation tests via Gradle as usual. | |
* | |
* When running UI tests via adb, add a *listener* execution argument to the command line for running | |
* the UI tests: | |
* `-e listener com.example.CrashingRunListener`. The full command | |
* line should look something like this: | |
* | |
* ``` | |
* adb shell am instrument \\ | |
* -w com.android.foo/android.support.test.runner.AndroidJUnitRunner \\ | |
* -e listener com.example.CrashingRunListener | |
* ``` | |
*/ | |
internal class CrashingRunListener : RunListener() { | |
@Volatile | |
private lateinit var bundle: Bundle | |
@Volatile | |
private var isTestRunning = false | |
override fun testRunStarted(description: Description) { | |
val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()!! | |
Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> | |
if (isTestRunning) { | |
isTestRunning = false | |
reportTestFailure( | |
"Instrumentation test failed due to uncaught exception in thread [${thread.name}]:\n" + | |
Log.getStackTraceString(throwable) | |
) | |
} | |
defaultHandler.uncaughtException(thread, throwable) | |
} | |
} | |
override fun testStarted(description: Description) { | |
val testClass = description.className | |
val testName = description.methodName | |
bundle = Bundle() | |
bundle.putString(Instrumentation.REPORT_KEY_IDENTIFIER, CrashingRunListener::class.java.name) | |
bundle.putString(InstrumentationResultPrinter.REPORT_KEY_NAME_CLASS, testClass) | |
bundle.putString(InstrumentationResultPrinter.REPORT_KEY_NAME_TEST, testName) | |
isTestRunning = true | |
} | |
override fun testFinished(description: Description?) { | |
isTestRunning = false | |
} | |
/** | |
* Reports that the test has failed, with the provided [message]. | |
*/ | |
private fun reportTestFailure(message: String) { | |
bundle.putString(InstrumentationResultPrinter.REPORT_KEY_STACK, message) | |
InstrumentationRegistry.getInstrumentation() | |
.sendStatus(InstrumentationResultPrinter.REPORT_VALUE_RESULT_FAILURE, bundle) | |
} | |
} |
@uberbinge : Friends don't let friends believe Lint lies ;) .
This still works just fine for us, Lint can go fork itself.
The right approach here would be for Espresso to add an API that supports adding a custom failure at the end of a successful test, without having to resort to a rule. Don't hesitate to file a ticket to the Espresso project.
They could also add support for failing tests when unhandled exceptions fire.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, thanks for the gist ❤️ we benefitted from it a lot. Today when we updated Espresso to 3.5.1 lint fails with:
If you happen to face the same issue and updated your own codebase, would appreciate if you can update the gist whenever you can 🙇 🙏