【问题标题】:SBT + JaCoCo not covering all the "jacoco.includes" classes from different projectsSBT + JaCoCo 没有涵盖来自不同项目的所有“jacoco.includes”类
【发布时间】:2017-08-03 19:57:18
【问题描述】:

我有一个 SBT(Play Framework)多项目应用程序设置,如下所示。所有子模块都在modules 下,但涵盖所有子模块的所有测试用例都在“根”项目中。

|-application
    |-src
    |-conf
    |-modules
    |   |-proj1
    |   |   |-src
    |   |   |-conf
    |   |   |-target
    |   |-proj2
    |   |   |-src
    |   |   |-conf
    |   |   |-target
    |   |-proj3
    |   |   |-src
    |   |   |-conf
    |   |   |-target
    |   |-proj4
    |       |-src
    |       |-conf
    |       |-target
    |-test
    |   |-src //I have test cases of all other projs here
    |-build.sbt
    |-plugins.sbt

我的build.sbt 看起来像这样。

name := """my-proj"""

lazy val IntegrationTest = config("it") extend(Test)

lazy val commonSettings = jacoco.settings ++ itJacoco.settings ++ Seq(
  organization := "me.abc",
  version := "0.1.0",
  scalaVersion := "2.11.7",
  crossPaths := false,
  routesGenerator := InjectedRoutesGenerator
)
lazy val appDependencies = Seq(
  cache,
  "org.mockito" % "mockito-all" % "1.10.19"
)

lazy val scalacheck = "org.scalacheck" %% "scalacheck" % "1.13.4"

lazy val aaRoot = (project in file(".")).configs(IntegrationTest).settings(commonSettings: _*).settings(
  libraryDependencies ++= appDependencies,
  libraryDependencies += scalacheck % Test,
  parallelExecution in Test := false,
  javaOptions in Test += "-Dconfig.file=conf/" + Option(System.getProperty("test.config")).getOrElse("application") + ".conf",
  parallelExecution in jacoco.Config := false,
  jacoco.includes in jacoco.Config := Seq("./modules/*/target/classes/com/me/**/*"),
  parallelExecution in itJacoco.Config := false,
  itJacoco.includes in itJacoco.Config := Seq("./modules/*/target/classes/com/me/**/*"),
  Keys.fork in itJacoco.Config := true,
  Keys.fork in jacoco.Config := true
).enablePlugins(PlayJava).disablePlugins(plugins.JUnitXmlReportPlugin).dependsOn(
  proj1 % "compile->compile",
  proj2 % "compile->compile",
  proj3 % "compile->compile",
  proj4 % "compile->compile",
).aggregate(
    proj1,
    proj2,
    proj3,
    proj4
  )

lazy val proj1 = (project in file("modules/proj1")).configs(IntegrationTest).settings(commonSettings: _*).settings(
  libraryDependencies ++= appDependencies
).enablePlugins(PlayJava)


fork in run := false

PlayKeys.externalizeResources := false

如您所见,在aaRoot 中,我正在尝试jacoco.includes 其他模块目标文件夹中的类文件(我尝试了其他几种方法,但没有任何效果)。所有测试用例都运行良好,但jacoco 无法涵盖任何内容。

[info] ------- Jacoco Coverage Report --------
[info] 
[info] Lines: 0% (>= required 0.0%) covered, 0 of 0 missed, OK
[info] Instructions: 0% (>= required 0.0%) covered, 0 of 0 missed, OK
[info] Branches: 0% (>= required 0.0%) covered, 0 of 0 missed, OK
[info] Methods: 0% (>= required 0.0%) covered, 0 of 0 missed, OK
[info] Complexity: 0% (>= required 0.0%) covered, 0 of 0 missed, OK
[info] Class: 0% (>= required 0.0%) covered, 0 of 0 missed, OK
[info] Check /Users/RP/application/target/jacoco for detail report

很明显,jacoco.includes 没有查看我要求查看的任何课程。

我尝试了很多方法并尝试使用it-jacoco:cover,但没有任何效果。任何提示或帮助都会受到欢迎。

【问题讨论】:

    标签: playframework playframework-2.0 sbt jacoco


    【解决方案1】:

    这是一个棘手的问题。我解决了我的问题并让jacocosbt 使用我的项目设置,我认为我的项目设置并不算太糟糕而且很正常。

    我有的是,一个根项目下的几个子项目,所有子项目相关的测试用例都在root/test中,这样我就可以测试跨模块的功能测试了。

    解决方案 在阅读并理解了 jacocosbt 插件的源代码后,我意识到它主要取决于两个方面。一个是classesToCover,另一个是“仪器类”。

    对于“要检测的类”,它取决于products in Compile,这是您所在的当前项目中的“target/classes”文件夹。在我的情况下,“root/target/classes”什么都没有,并且有没有什么可做的。我所有的课程都在“root/modules/module1/target/classes”等中。

    我所需要的只是覆盖此行为。第一个很简单,第二个可以解决。

    在我的build.sbt中,我必须添加以下修改

    //Gets all the target/classes directories from sub projects
    lazy val myProducts = Def.task {
      streams.value.log.info("Constructing the products!!!")
      val finder: PathFinder = ((baseDirectory.value / "modules") ** "target" * "classes") filter {_.getAbsolutePath.indexOf("/project/") == -1}
      finder.get
    }
    
    //Gets the classesToCover from all the sub projects
    lazy val myClassesToCover = Def.task {
      val targetFolders: Seq[java.io.File] = myProducts.value
      val inclFilters = Seq("*") map GlobFilter.apply
      val exclFilters = Seq("Routes*","*Routes*","*Reverse*","*anonfun*", "*routes*") map GlobFilter.apply
    
      targetFolders flatMap (classes => {
         PathFinder(classes) ** new FileFilter {
           def accept(f: File) = IO.relativize(classes, f) match {
             case Some(file) if !f.isDirectory && file.endsWith(".class") =>
               val name = sbt.inc.Locate.toClassName(file)
               inclFilters.exists(_ accept name) && !exclFilters.exists(_ accept name)
             case _ => false
      }
         } get
      })
    }
    
    //Add them as settings for my root project
    
    lazy val root = (project in file(".")).settings(commonSettings: _*).settings(
      jacoco.settings,
      parallelExecution in jacoco.Config := false,
      Keys.fork in jacoco.Config := true,
      jacoco.classesToCover in jacoco.Config ++= myClassesToCover.value,
      products in Compile ++= myProducts.value
    ).enablePlugins(PlayJava).disablePlugins(plugins.JUnitXmlReportPlugin).dependsOn(
      module1 % "test->test;compile->compile",
      module2 % "test->test;compile->compile"
    ).aggregate(
        module1,
        module2
    )
    

    由于 sbt compile 任务依赖于 products 目标,我们应该始终像 >sbt compile jacoco:cover 一样先运行编译。

    我仅使用 jacocosbt 插件版本 2.1.6 对此进行了测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      • 2016-04-13
      • 2020-04-20
      • 2019-02-21
      • 2016-06-27
      • 2014-01-04
      相关资源
      最近更新 更多