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 index 18e504dd6..d944b9aa4 100644 --- a/sbt/src/sbt-test/tests/junit-xml-report/build.sbt +++ b/sbt/src/sbt-test/tests/junit-xml-report/build.sbt @@ -8,18 +8,21 @@ val checkNoReport = taskKey[Unit]("Check that no reports are present") val oneSecondReportFile = "target/test-reports/a.pkg.OneSecondTest.xml" val failingReportFile = "target/test-reports/another.pkg.FailingTest.xml" +val flatSuiteReportFile = "target/test-reports/my.scalatest.MyFlatSuite.xml" +val nestedSuitesReportFile = "target/test-reports/my.scalatest.MyNestedSuites.xml" + lazy val root = (project in file(".")). settings( scalaVersion := "2.11.8", libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test, - + libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.6" % Test, // TODO use matchers instead of sys.error checkReport := { val oneSecondReport = XML.loadFile(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) @@ -28,11 +31,31 @@ lazy val root = (project in file(".")). if( (failingReport \ "@name").text != "another.pkg.FailingTest" ) sys.error("wrong test name: " + (failingReport \ "@name").text) // TODO more checks -> the two test cases with time etc.. + val scalaTestFlatReport = XML.loadFile(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(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( + oneSecondReportFile, + failingReportFile, + flatSuiteReportFile, + nestedSuitesReportFile + )) { + if( file(f).exists() ) sys.error(f + " should not exist") + } } ) 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 ce6ba25bf..0d83f3ce0 100644 --- a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala +++ b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala @@ -1,13 +1,19 @@ 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 testing.{ + Event => TEvent, + NestedTestSelector, + Status => TStatus, + OptionalThrowable, + TestSelector +} import sbt.protocol.testing.TestResult /** @@ -75,8 +81,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 }> {