我是Scala和JVM的新手,我想为记录器编写单元测试,但是当我从终端运行sbt test
时会遇到这个错误。
java.lang.ClassCastException: class org.apache.logging.slf4j.Log4jLogger cannot be cast to class ch.qos.logback.classic.Logger (org.apache.logging.slf4j.Log4jLogger and ch.qos.logback.classic.Logger are in unnamed module of loader 'app')
与此警告
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.16.0/log4j-slf4j-impl-2.16.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.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 [org.apache.logging.slf4j.Log4jLoggerFactory]
但是当我从IntelliJ运行测试时,它通过了。
我的测试代码如下
import org.scalatest._
import flatspec._
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.read.ListAppender
import org.slf4j.LoggerFactory
class MyAppSuite extends AnyFlatSpec {
it should "Log message" in {
object MyApp {
val LOGGER = LoggerFactory.getLogger(classOf[ILoggingEvent])
}
class MyApp {
def hello(word: String): Unit = {
MyApp.LOGGER.info(s"Word is ${word}")
}
}
val appender = new ListAppender[ILoggingEvent]
appender.start()
val logger = MyApp.LOGGER.asInstanceOf[Logger]
logger.addAppender(appender)
val myApp = new MyApp
myApp.hello("wow")
val logsList = appender.list
assert(logsList.size() === 1)
val logEvent = logsList.get(0)
assert(logEvent.getLevel.levelStr === "INFO")
assert(logEvent.getMessage === "Word is wow")
}
}
我在build.sbt
中的依赖性
...
scalaVersion := "2.12.14"
val log4jVersion = "2.16.0"
val loggingDependencies = Seq(
"org.slf4j" % "slf4j-api" % "1.7.36",
"org.apache.logging.log4j" % "log4j-api" % log4jVersion,
"org.apache.logging.log4j" % "log4j-core" % log4jVersion,
"org.apache.logging.log4j" % "log4j-slf4j-impl" % log4jVersion
)
val testingDependencies = Seq(
"org.scalamock" %% "scalamock" % "5.2.0" % Test,
"org.scalatest" %% "scalatest" % "3.2.12" % Test,
"ch.qos.logback" % "logback-classic" % "1.2.11" % Test,
)
libraryDependencies ++= loggingDependencies ++ testingDependencies
excludeDependencies ++= Seq(
"org.slf4j" % "slf4j-log4j12"
)
当我从IntelliJ运行测试时,我看到了以下警告
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/yl3/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.16.0/log4j-slf4j-impl-2.16.0.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]
我在Java中发现了类似的日志测试
因此,我假设它应该在Scala中工作,但不确定为什么强制转换不起作用。使用其他库测试日志记录有任何建议或其他方法吗?
发布于 2022-08-02 05:43:54
来自SLF4J的警告消息非常有用。在这两种情况下,它都说在类路径中加载了几个日志库,这可能会给带来麻烦。
在查看详细信息时,它甚至会指出选择哪个库作为SLF4J实现:
在您的SBT测试中,它选择了Logback:Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
这解释了期望日志库是Logback的代码在IntelliJ测试中工作,而不是在SBT运行时工作。
当类路径中有几个日志实现时,无法确定哪个SLF4J将使用.。
现在,让我们澄清您在构建定义中的依赖关系:
slf4j-api
:the SLF4J API、log4j-api
:log4j 2 API、log4j-core
:log4j 2 implementationlog4j-slf4j-impl
:绑定以使SLF4J写入日志与log4j 2 implementationlogback-core
和logback-classic
:Logback实现(Logback附带一个绑定以使SLF4J写日志与Logback自动),并且您已经排除了slf4j-log4j12
,它是用log4j 1.2 implementation.制作SlF4J写日志的绑定
溶液
如果您不需要多个日志库(这是情况下99%的日志库),那么只要选择要使用的实现,它似乎就是Logback,因为您有特定于Logback的代码。然后删除其他库实现和绑定依赖项。
这意味着在您的情况下删除log4j-core
和log4j-slf4j-impl
。
但是,您可能仍然有依赖于log4j 2 API来记录内容的代码(例如,其他依赖项)。因此,您可能需要添加绑定库,以使log4j 2日志通过SlF4J编写。为此,添加log4j-to-slf4j-2.x
依赖项。
注意:如果出于某种奇怪的原因,您需要几个日志实现,那么不要在代码中假设它是其中之一,也不要通过处理强制转换异常来处理它。
https://stackoverflow.com/questions/73199070
复制相似问题