Using slf4j-test in unit tests: How to arrange the classpath so it _doesn't_ include the standard logger?

Answered

I'm trying to use slf4j-test (http://projects.lidalia.org.uk/slf4j-test/) with IDEA 15.0.2 (and testing if that matters).  When running my unit tests I'm getting the slf4j error "multiple bindings" found (http://www.slf4j.org/codes.html#multiple_bindings ) (and of course, it is randomly picking the wrong one).

I have the project structure/modules/dependencies set so that:

  • slf4j-api is a provided dependency
  • slf4j-log4j and log4j are runtime dependencies
  • slf4j-test is a test dependency

The problem, I believe, is that runtime dependencies are also included during test runs, so both slf4j-log4j and slf4j-test are in the classpath for unit tests. But I want to exclude slf4j-log4j from unit test runs (because I'm going to be using slf4j-test).

How can I arrange this?  Thanks! -- David

(Gradle can arrange this with a line like "configurations { testRuntime { exclude module:'slf4j-log4j12' }}" but that's apparently not respected by the Gradle support in 15.0.2.)

6 comments
Comment actions Permalink

I should add that if I manually delete slf4j-log4j as a module dependency in project structure/modules/dependencies then it comes back the next time I hit refresh in the Gradle tool window.  (Oh, yeah, I'm importing this project from Gradle.)

0
Comment actions Permalink

https://youtrack.jetbrains.com/issue/IDEA-122982 may be related as proper excludes support was added only in IDEA 16. Did you check if it works in 16 EAP: https://confluence.jetbrains.com/display/IDEADEV/IDEA+16+EAP ?

0
Comment actions Permalink

The problem seems to be that IntelliJ does not respect the scope of the dependency – compile, testCompile, runtime, testRuntime, etc. – when generating the classpath for the run configs. Instead, it seems that all dependencies, no matter where they are declared, end up on the classpath. (I'm still seeing this on IntelliJ IDEA 2017.2.5 Build #IU-172.4343.14.)

I worked around this issue myself by copy-and-pasting the org.slf4j.impl.StaticLoggerBinder from slf4j-test into my own project's test sources. Since IntelliJ does always add your own classes to the classpath first, this effectively forced slf4j-test to always be the loaded slf4j binding, and leading to the correct results.

0
Comment actions Permalink

IntelliJ IDEA certainly respects the scope of the dependencies. If it's not true for your projects, please report at https://youtrack.jetbrains.com/issues/IDEA with the reproducible test case.

0
Comment actions Permalink

FYI, this is still a problem.

It seems to be by design: https://www.jetbrains.com/help/idea/dependencies.html

See quote below. There is no "testCompile" or "testRuntime" scope in IntelliJ, like there is in Gradle. All scopes are added to the classpath for "Tests, when run".

------------------------------------------------------------------------------------------------------------------------------------------------------

The following table summarizes the classpath information for the possible dependency scopes.

Scope

Sources,
when compiled

Sources,
when run

Tests,
when compiled

Tests,
when run

Compile

+

+

+

+

Test

-

-

+

+

Runtime

-

+

-

+

Provided

+

-

+

+

1
Comment actions Permalink

@Scott Davis can you provide a sample project showing the issue? Please describe the result you get when run from IDE and when run from Gradle command line.

Make sure you have Settings (Preferences on macOS) | Build, Execution, Deployment | Build Tools | Gradle | Create separate module per source set option enabled. This ways IDE creates separate module with each source set (main and test one) which always has it's own classpath - so there should be no issues with dependencies scope.

0

Please sign in to leave a comment.