'How to configure gradle to use logback-classic ONLY for unit tests in Android?

I have an Android app thich uses slf4j + logback. Gradle file looks like this:

...
compile('com.github.tony19:logback-android-core:1.1.1-6') {
    exclude group: 'ch.qos.logback.core.net'
}

compile('com.github.tony19:logback-android-classic:1.1.1-6') {
    exclude group: 'ch.qos.logback.core.net'
}

compile 'org.slf4j:slf4j-api:1.7.25'

And I have logback.xml in assets/. When I run the app logging work as expected. Recently I've decided to add new unit tests (regular, not android unit tests) but I saw that log messages are not shown.

I've added following to the gragle file:

testCompile('ch.qos.logback:logback-classic:1.2.3') {
    exclude group: 'com.github.tony19'
}

and now log messages are shown but on each run of the unit tests I get this warning:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/o/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.3/7c4f3c474fb2c041d8028740440937705ebb473a/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/o/.gradle/caches/modules-2/files-2.1/com.github.tony19/logback-android-classic/1.1.1-6/614c66c9ece69eef48c65a8558de4fd7266d9f69/logback-android-classic-1.1.1-6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

Is there a way to specify exclusively which slf4j binding to be used for the regular app runs and which for unit tests only (or any other solution)?

Dependencies graph:

compile - Classpath for compiling the main sources.
+--- com.bolyartech.forge.android:forge-android:7.1.0
|    +--- com.bolyartech.forge:base:5.1.0
|    |    +--- org.slf4j:slf4j-api:1.7.7 -> 1.7.25
|    |    +--- com.darwinsys:hirondelle-date4j:1.5.1
|    |    +--- com.google.guava:guava:20.0
|    |    +--- javax.inject:javax.inject:1
|    |    \--- com.squareup.okhttp3:okhttp:3.1.2
|    |         \--- com.squareup.okio:okio:1.6.0
|    +--- com.google.dagger:dagger:2.9
|    |    \--- javax.inject:javax.inject:1
|    +--- com.android.support:support-annotations:25.3.1 -> 26.0.1
|    +--- javax.annotation:jsr250-api:1.0
|    +--- com.android.support.test.espresso:espresso-idling-resource:2.2.2
|    \--- net.sourceforge.streamsupport:streamsupport:1.5.1
+--- com.bolyartech.scram_sasl:scram_sasl:2.0.1
+--- com.android.support:multidex:1.0.1
+--- com.squareup:otto:1.3.8
+--- com.google.code.gson:gson:2.7
+--- com.github.franmontiel:PersistentCookieJar:v0.9.3
|    \--- com.squareup.okhttp3:okhttp:3.1.2 (*)
+--- com.github.tony19:logback-android-core:1.1.1-6
+--- com.github.tony19:logback-android-classic:1.1.1-6
|    +--- com.github.tony19:logback-android-core:1.1.1-6
|    \--- com.github.tony19:apktool-lib:1.4.4-3
|         \--- com.google.android:android:2.1_r1
|              +--- commons-logging:commons-logging:1.1.1
|              +--- org.apache.httpcomponents:httpclient:4.0.1
|              |    +--- org.apache.httpcomponents:httpcore:4.0.1
|              |    +--- commons-logging:commons-logging:1.1.1
|              |    \--- commons-codec:commons-codec:1.3
|              +--- org.khronos:opengl-api:gl1.1-android-2.1_r1
|              +--- xerces:xmlParserAPIs:2.6.2
|              \--- xpp3:xpp3:1.1.4c
+--- ch.acra:acra:4.7.0
|    \--- com.android.support:support-v4:23.0.1 -> 26.0.1
|         +--- com.android.support:support-compat:26.0.1
|         |    \--- com.android.support:support-annotations:26.0.1
|         +--- com.android.support:support-media-compat:26.0.1
|         |    +--- com.android.support:support-annotations:26.0.1
|         |    \--- com.android.support:support-compat:26.0.1 (*)
|         +--- com.android.support:support-core-utils:26.0.1
|         |    +--- com.android.support:support-annotations:26.0.1
|         |    \--- com.android.support:support-compat:26.0.1 (*)
|         +--- com.android.support:support-core-ui:26.0.1
|         |    +--- com.android.support:support-annotations:26.0.1
|         |    \--- com.android.support:support-compat:26.0.1 (*)
|         \--- com.android.support:support-fragment:26.0.1
|              +--- com.android.support:support-compat:26.0.1 (*)
|              +--- com.android.support:support-core-ui:26.0.1 (*)
|              \--- com.android.support:support-core-utils:26.0.1 (*)
+--- org.slf4j:slf4j-api:1.7.25
+--- javax.inject:javax.inject:1
+--- javax.annotation:jsr250-api:1.0
+--- com.google.dagger:dagger:2.9 (*)
\--- com.android.support:appcompat-v7:26.0.1
     +--- com.android.support:support-annotations:26.0.1
     +--- com.android.support:support-v4:26.0.1 (*)
     +--- com.android.support:support-vector-drawable:26.0.1
     |    +--- com.android.support:support-annotations:26.0.1
     |    \--- com.android.support:support-compat:26.0.1 (*)
     \--- com.android.support:animated-vector-drawable:26.0.1
          +--- com.android.support:support-vector-drawable:26.0.1 (*)
          \--- com.android.support:support-core-ui:26.0.1 (*)


testCompile - Classpath for compiling the test sources.
+--- ch.qos.logback:logback-classic:1.2.3
|    +--- ch.qos.logback:logback-core:1.2.3
|    \--- org.slf4j:slf4j-api:1.7.25
+--- junit:junit:4.12
|    \--- org.hamcrest:hamcrest-core:1.3
\--- org.mockito:mockito-core:1.10.19
     +--- org.hamcrest:hamcrest-core:1.1 -> 1.3
     \--- org.objenesis:objenesis:2.1


Solution 1:[1]

With Android Gradle Plugin 3 and above, try to use following:

implementation 'org.slf4j:slf4j-api:1.7.25'   
runtimeOnly 'com.github.tony19:logback-android-core:1.1.1-6'

Solution 2:[2]

Dependency Scope

In the old version of gradle, the dependency scope of compile will be included in all classpaths of projects, i.e. including compilation, runtime, test compilation and test execution. So the two implementations of SLF4J class will be included in test execution.

SLF4J Binding

And because the implementation of SLF4J bindings, two bindings will causes an warning, SLF4J will randomly choose a binding, in this case, not logback.

Solution

So, the only way to solve the problem is to exclude logback-android from your test classpath.

In the new version of Gradle (4.0.2), we define logback-android in runtimeElements to avoid be used by test environment. In old version, it seems that we cann't solve this problem with gradle.

Ref

Solution 3:[3]

You need to exclude it on the root level, instead of the logback classic dependency:

configurations {
    testCompile.exclude group: 'com.github.tony19'
}

Solution 4:[4]

Exclude tony19 library from test classpath with

configurations {
  testImplementation.exclude group: 'com.github.tony19'
  //with testCompile the library is not used for compilation but used for running tests
}

dependencies {
  //logging
  implementation 'org.slf4j:slf4j-api:1.7.30'
  runtimeOnly 'com.github.tony19:logback-android:2.0.0'
  testImplementation group: 'ch.qos.logback', name: 'logback-classic', version:  '1.2.11'
}

Using testCompile.exclude still give the warning

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/raiser/.gradle/caches/transforms-3/5db974f19df3b652be1c75410514efb8/transformed/jetified-logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/raiser/.gradle/caches/transforms-3/f97ca29862548c3aa25d47e0ab6abbab/transformed/jetified-logback-android-2.0.0-runtime.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/raiser/.gradle/caches/transforms-3/17f8528b15b95f4e98b73ee7482c4884/transformed/jetified-logback-android-2.0.0/jars/classes.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ultraon
Solution 2 Community
Solution 3 highstakes
Solution 4 raisercostin