I'm writing an Android app in Android Studio using gradle (Kotlin DSL) for the build. My goal is to use SLF4J and redirect all logs from the application and third party libraries to logcat when running in Android but to the console or a file when running locally (i.e., in regular unit tests). My current best attempt uses these dependencies:
dependencies {
implementation("org.slf4j:slf4j-api:1.7.36")
implementation("org.slf4j:jul-to-slf4j:1.7.36")
runtimeOnly("org.slf4j:slf4j-android:1.7.36")
testRuntimeOnly("org.slf4j:slf4j-simple:1.7.36")
}
JUL logs from libraries are redirected to SLF4J, which should use the Android logcat output on the device but the simple console output in tests. Unfortunately I get both dependencies when running tests and end up with:
*** Caught exception: Method isLoggable in android.util.Log not mocked.
See https://developer.android.com/r/studio-ui/build/not-mocked for details.
In other words runtimeOnly dependencies are included when the tests run. Somehow, I need to get rid of the slf4j-android dependency in the regular unit tests.
The build.gradle.kts file uses the Android plugin, not the java plugin:
plugins {
id("com.android.application")
}
This is a stock Android configuration, but means solutions targeting the java plugin may not work. Android has three sets of sources: main for the real code, test for local unit tests and androidTest for unit tests running on an emulated device. I need the android implementation in main and androidTest, but the simple implementation in test.
See Different Gradle dependency for test than for compile, which is similar but still lacks a solution. EDIT: also see How to use logback in android?.
Ideally, I would like to learn how to include the right dependency for each configuration as described above in build.gradle.kts. However, if there is another solution where SLF4J can be configured to use logcat on the device and the console or files in tests that would also work.
Is there a way to do this? At first glance it should be a common thing as many Android apps need to include Java libraries and redirect their logs, but apparently not.
It is in fact possible to get rid of the Android dependency in the test configuration. The syntax is as follows.
dependencies {
implementation("org.slf4j:slf4j-api:1.7.36")
runtimeOnly("org.slf4j:jul-to-slf4j:1.7.36")
runtimeOnly("org.slf4j:slf4j-android:1.7.36")
testImplementation("org.slf4j:slf4j-simple:1.7.36")
}
configurations.testImplementation {
// Don't include two SLF4J implementations in unit tests
// Remove the logcat version, which doesn't work
exclude("org.slf4j", "slf4j-android")
}
This includes slf4j-android in main and androidTest, but removes it from test, where slf4j-simple is used. Here I include jul-to-slf4j as we are using it, but it is not a part of the solution.