diff --git a/notes/0.13.16/junit-report-nested-suites.markdown b/notes/0.13.16/junit-report-nested-suites.markdown new file mode 100644 index 000000000..2b84eeee0 --- /dev/null +++ b/notes/0.13.16/junit-report-nested-suites.markdown @@ -0,0 +1,5 @@ +### Bug fixes + +- Fixes ScalaTest nested suite test names being reported as "(It is not a test)". [#3154][3154] by [@jameskoch][@jameskoch] + + [@jameskoch]: https://github.com/jameskoch diff --git a/sbt/src/sbt-test/tests/junit-xml-report/build.sbt b/sbt/src/sbt-test/tests/junit-xml-report/build.sbt new file mode 100644 index 000000000..3657474e5 --- /dev/null +++ b/sbt/src/sbt-test/tests/junit-xml-report/build.sbt @@ -0,0 +1,3 @@ +scalaVersion := "2.11.8" + +libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.6" % "test" \ No newline at end of file diff --git a/sbt/src/sbt-test/tests/junit-xml-report/project/JUnitXmlReportTest.scala b/sbt/src/sbt-test/tests/junit-xml-report/project/JUnitXmlReportTest.scala index 77de82620..c72cb75a0 100644 --- a/sbt/src/sbt-test/tests/junit-xml-report/project/JUnitXmlReportTest.scala +++ b/sbt/src/sbt-test/tests/junit-xml-report/project/JUnitXmlReportTest.scala @@ -8,34 +8,61 @@ object JUnitXmlReportTest extends Build { val checkReport = taskKey[Unit]("Check the test reports") val checkNoReport = taskKey[Unit]("Check that no reports are present") - private val oneSecondReportFile = "target/test-reports/a.pkg.OneSecondTest.xml" - private val failingReportFile = "target/test-reports/another.pkg.FailingTest.xml" + private object JUnit { + val oneSecondReportFile = "target/test-reports/a.pkg.OneSecondTest.xml" + val failingReportFile = "target/test-reports/another.pkg.FailingTest.xml" + } + + private object ScalaTest { + val flatSuiteReportFile = "target/test-reports/my.scalatest.MyFlatSuite.xml" + val nestedSuitesReportFile = "target/test-reports/my.scalatest.MyNestedSuites.xml" + } lazy val root = Project("root", file("."), settings = defaultSettings ++ Seq( - scalaVersion := "2.9.2", - libraryDependencies += "com.novocode" % "junit-interface" % "0.10" % "test", + scalaVersion := "2.11.8", + libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test", // TODO use matchers instead of sys.error checkReport := { - val oneSecondReport = XML.loadFile(oneSecondReportFile) + val oneSecondReport = XML.loadFile(JUnit.oneSecondReportFile) if( oneSecondReport.label != "testsuite" ) sys.error("Report should have a root element.") // somehow the 'success' event doesn't go through... TODO investigate // if( (oneSecondReport \ "@time").text.toFloat < 1f ) sys.error("expected test to take at least 1 sec") - if( (oneSecondReport \ "@name").text != "a.pkg.OneSecondTest" ) sys.error("wrong test name: " + (oneSecondReport \ "@name").text) + if( (oneSecondReport \ "@name").text != "a.pkg.OneSecondTest" ) sys.error("wrong fixture name: " + (oneSecondReport \ "@name").text) // TODO more checks - val failingReport = XML.loadFile(failingReportFile) + val failingReport = XML.loadFile(JUnit.failingReportFile) if( failingReport.label != "testsuite" ) sys.error("Report should have a root element.") if( (failingReport \ "@failures").text != "2" ) sys.error("expected 2 failures") - if( (failingReport \ "@name").text != "another.pkg.FailingTest" ) sys.error("wrong test name: " + (failingReport \ "@name").text) + if( (failingReport \ "@name").text != "another.pkg.FailingTest" ) sys.error("wrong fixture name: " + (failingReport \ "@name").text) // TODO more checks -> the two test cases with time etc.. + val scalaTestFlatReport = XML.loadFile(ScalaTest.flatSuiteReportFile) + if( scalaTestFlatReport.label != "testsuite" ) sys.error("Report should have a root element.") + if( (scalaTestFlatReport \ "@tests").text != "2" ) sys.error("expected 2 tests") + if( (scalaTestFlatReport \ "@failures").text != "1" ) sys.error("expected 1 failures") + if( (scalaTestFlatReport \ "@name").text != "my.scalatest.MyFlatSuite" ) sys.error("wrong fixture name: " + (scalaTestFlatReport \ "@name").text) + + val nestedSuitesReport = XML.loadFile(ScalaTest.nestedSuitesReportFile) + if( nestedSuitesReport.label != "testsuite" ) sys.error("Report should have a root element.") + if( (nestedSuitesReport \ "@tests").text != "2" ) sys.error("expected 2 tests") + if( (nestedSuitesReport \ "@failures").text != "1" ) sys.error("expected 1 failures") + if( (nestedSuitesReport \ "@name").text != "my.scalatest.MyNestedSuites" ) sys.error("wrong fixture name: " + (nestedSuitesReport \ "@name").text) + val actualTestName = (nestedSuitesReport \ "testcase").map(t => (t \ "@name").text) + if( actualTestName.toSet != Set("MyInnerSuite.Inner passing test should pass", "MyInnerSuite.Inner failing test should fail")) sys.error(s"wrong test names: ${actualTestName.mkString(", ")}") + // TODO check console output is in the report }, checkNoReport := { - if( file(oneSecondReportFile).exists() ) sys.error(oneSecondReportFile + " should not exist") - if( file(failingReportFile).exists() ) sys.error(failingReportFile + " should not exist") + for (f <- Seq( + JUnit.oneSecondReportFile, + JUnit.failingReportFile, + ScalaTest.flatSuiteReportFile, + ScalaTest.nestedSuitesReportFile + )) { + if( file(f).exists() ) sys.error(f + " should not exist") + } } )) } \ No newline at end of file diff --git a/sbt/src/sbt-test/tests/junit-xml-report/src/test/scala/tests.scala b/sbt/src/sbt-test/tests/junit-xml-report/src/test/scala/junit-tests.scala similarity index 100% rename from sbt/src/sbt-test/tests/junit-xml-report/src/test/scala/tests.scala rename to sbt/src/sbt-test/tests/junit-xml-report/src/test/scala/junit-tests.scala diff --git a/sbt/src/sbt-test/tests/junit-xml-report/src/test/scala/scala-tests.scala b/sbt/src/sbt-test/tests/junit-xml-report/src/test/scala/scala-tests.scala new file mode 100644 index 000000000..affe50e3f --- /dev/null +++ b/sbt/src/sbt-test/tests/junit-xml-report/src/test/scala/scala-tests.scala @@ -0,0 +1,25 @@ +import org.scalatest._ + +package my.scalatest { + class MyFlatSuite extends FlatSpec { + "Passing test" should "pass" in { + + } + + "Failing test" should "fail" in { + sys.error("wah wah") + } + } + + class MyInnerSuite(arg: String) extends FlatSpec { + "Inner passing test" should "pass" in { + + } + + "Inner failing test" should "fail" in { + sys.error("wah wah") + } + } + + class MyNestedSuites extends Suites(new MyInnerSuite("arrrrrg!")) +} \ No newline at end of file diff --git a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala index e4797b754..050966223 100644 --- a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala +++ b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala @@ -1,13 +1,13 @@ package sbt -import java.io.{ IOException, StringWriter, PrintWriter, File } +import java.io.{ File, IOException, PrintWriter, StringWriter } import java.net.InetAddress import java.util.Hashtable import scala.collection.mutable.ListBuffer import scala.util.DynamicVariable -import scala.xml.{ Elem, Node => XNode, XML } -import testing.{ Event => TEvent, Status => TStatus, OptionalThrowable, TestSelector } +import scala.xml.{ Elem, XML, Node => XNode } +import testing.{ NestedTestSelector, OptionalThrowable, TestSelector, Event => TEvent, Status => TStatus } /** * A tests listener that outputs the results it receives in junit xml @@ -70,8 +70,9 @@ class JUnitXmlTestsListener(val outputDir: String) extends TestsListener { { for (e <- events) yield selector.testName.split('.').last - case _ => "(It is not a test)" + case selector: TestSelector => selector.testName.split('.').last + case nested: NestedTestSelector => nested.suiteId().split('.').last + "." + nested.testName() + case other => s"(It is not a test it is a ${other.getClass.getCanonicalName})" } } time={ (e.duration() / 1000.0).toString }> {