Подтвердить что ты не робот

Сравните scala.xml.Elem объект в unit test

У меня есть два объекта scala.xml.Elem (фактический, ожидаемый). Я использую JUnit 4, но также включил XMLUnit 1.3.

Есть ли простой способ сравнить два объекта для равенства, игнорируя порядок атрибутов и несущественные пробелы в XML?

Я попробовал XMLUnit.assertXMLEqual(), но он жалуется, что типы scala.xml.Elem.

Я знаю, что я могу использовать equals или ==, но я бы хотел, чтобы утверждение, подтверждающее утверждение, выдает два значения, когда они не равны. Если я использую assertTrue(actual.equals(expected)), и они не равны, единственным выходом будет "утверждение не выполнено".

4b9b3361

Ответ 1

Используйте версию assertTrue, которая позволяет передавать пользовательские сообщения

public static void assertTrue(java.lang.String message,
                              boolean condition)

и (например) diff для создания строки с узлами descendand, которые не равны

scala> val xml1 = <person><name>john</name><lastname>smith</lastname></person>
xml1: scala.xml.Elem = <person><name>john</name><lastname>smith</lastname></person>

scala> val xml2 = <person><name>jane</name><lastname>smith</lastname></person>
xml2: scala.xml.Elem = <person><name>jane</name><lastname>smith</lastname></person>

scala> assert(xml1 == xml2, xml1.child diff xml2.child mkString(", "))
java.lang.AssertionError: assertion failed: <name>john</name>
        at scala.Predef$.assert(Predef.scala:91)
        at .<init>(<console>:8)
        at .<clinit>(<console>)

Ответ 2

Если вы хотите сравнить с объектами XML Elem, игнорируя пробелы, вы можете удалить из них пробелы с помощью метода scala.xml.Utility.trim.

scala> val a = <foo>bar</foo>
a: scala.xml.Elem = <foo>bar</foo>

scala> val b = <foo>   bar   </foo>
b: scala.xml.Elem = <foo>   bar   </foo>

scala> a == b
res8: Boolean = false

scala> import scala.xml.Utility.trim
import scala.xml.Utility.trim

scala> trim(a) == trim(b)
res9: Boolean = true

Scala не заботится о порядке атрибутов, если вы используете XML-литералы:

scala> val a = <foo first="1" second="2" />
a: scala.xml.Elem = <foo first="1" second="2"></foo>

scala> val b = <foo second="1" first="1"  />
b: scala.xml.Elem = <foo first="1" second="1"></foo>

scala> a == b
res22: Boolean = true

Я бы порекомендовал ScalaTest для модульного тестирования там у вас есть ShouldMatchers:

// Scala repl started with scalatest-1.2.jar in the classpath

scala> val a = <foo>bar</foo>
a: scala.xml.Elem = <foo>bar</foo>

scala> val b = <foo>bar</foo>
b: scala.xml.Elem = <foo>bar</foo>

scala> a should equal(b)

scala> val b = <foo>bar2</foo>
b: scala.xml.Elem = <foo>bar2</foo>

scala> a should equal(b)
org.scalatest.TestFailedException: <foo>bar</foo> did not equal <foo>bar2</foo>
    at org.scalatest.matchers.Matchers$class.newTestFailedException(Matchers.scala:148)
    at org.scalatest.matchers.ShouldMatchers$.newTestFailedException(ShouldMatchers.scala:2329)
    at org.scalatest.matchers.ShouldMatchers$ShouldMethodHelper$.shouldMatcher(ShouldMatchers.scala:871)
    at org.scalatest.matchers.ShouldMatchers$SeqShouldWrapper.should(ShouldMatchers.scala:1724)
    at .<init>(<console>:15)
    at .<clinit>(<console>)
    at RequestResult$.<init>(<console>:9)
    at RequestResult$.<clinit>(<console>)
    at RequestResult$scala_repl_result(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.Delega...

Ответ 3

Ранние ответы были полезны для меня, хотя я обнаружил, что иногда мне хотелось проверить более крупный фрагмент XML, а сравнение сбоев, показывающее, что оба фрагмента XML были немного трудны для чтения. Этот метод сначала попытается скомпенсировать дочерние элементы, чтобы сравнить их, поэтому, если глубоко вложенный элемент неверен, он будет показывать гораздо более краткими ошибками. В зависимости от вашего XML это может не дать вам достаточно контекста для работы там, где он действительно не работает, но я считаю это полезным.

/** Check that the XMLs are the same, ignoring empty text nodes (whitespace). */
private def assertEqual(actual: xml.Node, expected: xml.Node) {

    def recurse(actual: xml.Node, expected: xml.Node) {
        // depth-first checks, to get specific failures
        for ((actualChild, expectedChild) <- actual.child zip expected.child) {
            recurse(actualChild, expectedChild)
        }
        actual should be (expected)
    }

    recurse(scala.xml.Utility.trim(actual), scala.xml.Utility.trim(expected))

}

Ответ 4

Я изменил код @Nick для работы с JDom2. В его коде из-за того, как работает zip, если в expectedXML actualXML есть конечные элементы, которых нет в actualXML, тест проходит actualXML. Я исправил эту ошибку и сделал необязательным сравнение конечных элементов:

trait XMLTest extends XMLSupport {
  /** Verify that the XMLs are the same, regardless of attribute or element ordering and ignoring whitespace. */
  def assertEqual(actual: Element, expected: Element, ignoreTrailingElements: Boolean=false): Assertion = {
    // depth-first comparison
    def recurse(actual: Element, expected: Element): Assertion = {
      import scala.collection.JavaConverters._
      val actualChildren: Seq[Element] = actual.getChildren.asScala.sortBy(_.getName)
      val expectedChildren: Seq[Element] = expected.getChildren.asScala.sortBy(_.getName)
      (actualChildren zip expectedChildren) foreach { case (actualChild, expectedChild) =>
        recurse(actualChild, expectedChild)
      }
      actual.getName shouldEqual expected.getName
      actual.getTextNormalize shouldEqual expected.getTextNormalize
      actual.getAttributes.asScala.map(_.toString).sorted shouldEqual expected.getAttributes.asScala.map(_.toString).sorted
      if (!ignoreTrailingElements && actualChildren.size < expectedChildren.size) {
        val diff = expectedChildren.drop(actualChildren.size)
        fail("Extra XML children found: " + prettyPrint(diff))
      } else succeed
    }

    recurse(actual, expected)
  }
}

Я написал эту черту, чтобы смешаться с тестовым кодом:

trait XMLSupport {
  import org.jdom2.output.{Format, XMLOutputter}

  def prettyPrint(doc: Document): String = {
    val xmlOutput = new XMLOutputter()
    xmlOutput.setFormat(Format.getPrettyFormat)
    xmlOutput.outputString(doc)
  }

  def prettyPrint(elements: Seq[Element]): String = {
    import scala.collection.JavaConverters._

    val xmlOutput = new XMLOutputter()
    xmlOutput.setFormat(Format.getPrettyFormat)
    xmlOutput.outputString(elements.asJava)
  }
}

Я вызвал тест следующим образом:

class XmlTest extends WordSpec with MustMatchers {
  // test code here
  assertEqual(actualXML.getRootElement, expectedXML.getRootElement, ignoreTrailingElements=true)
}