Сравните объект scala.xml.Elem в модульном тесте - PullRequest
13 голосов
/ 24 ноября 2010

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

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

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

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

Ответы [ 4 ]

18 голосов
/ 24 ноября 2010

Если вы хотите сравнить объекты 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...
10 голосов
/ 24 ноября 2010

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

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

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

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>)
1 голос
/ 17 сентября 2013

Предыдущие ответы были полезны для меня, хотя я обнаружил, что иногда мне хотелось проверить больший фрагмент 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))

}
0 голосов
/ 05 июня 2019

Я изменил код @ Ника для работы с JDom2 . В его коде из-за того, как работает zip, если expectedXML имеет конечные элементы, которых нет в 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)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...