2012-08-25 11 views
10

Ich benutze Jaxb 2.0 API ohne XSD, und habe das Inhaltsmodell mit Anmerkungen erstellt. Ich möchte einen Junit-Test für die Klasse schreiben, die das Marshalling durchführt. Mein ursprünglicher Plan war, den erwarteten XML-String mit dem tatsächlichen für die Behauptung zu vergleichen (offensichtlichste Wahl). Aber ich finde, dass das Marshalling XML erzeugt, wo Eigenschaften/Attribut-Reihenfolge nicht vorhersehbar ist (eigentlich weiß ich nicht, was die Standard-Reihenfolge ist). Wenn dies der Fall ist, kann ich keine vordefinierte xml-Zeichenfolge annehmen und diese dann mit der gemarshalltem vergleichen. Ein anderer Weg, den ich für die Durchsetzung der Marshaller-Klasse dachte, war wie folgt:Wie schreibe ich einen Komponententest für JAXB 2.0 Marshalling

1-Inhalt erstellen Modell.

2-Marshall es.

3-Unmarshall der in Schritt 2 erstellten XML-Datei, um das Modell zu erhalten.

4-Do-Bestätigung basierend auf Modell in Schritt 1 und Schritt 3 für Eigenschaften/Attribute.

Aber ich finde immer noch nicht zufriedenstellend. Was wäre der richtige Weg, um einen Junit-Test für das Marshalling in diesem Szenario zu schreiben?

Obwohl die eigentliche Anwendung, die die Marshalled-XML verwendet, nicht von der XML-Eigenschaften/Attribut-Reihenfolge abhängig ist, scheint der Junit-Test jedoch knifflig zu sein.

Dank

Antwort

6

ich auf Ihre Frage gestolpert, während für die gleiche Sache googeln. Wenn diese gefunden post, aber nicht die Idee, die generierte XML anschließend "parse". Nach dem Sieben durch den JAXB Javadoc fand ich einen Ansatz, den ich sehr mag. Ein JAXB Marshaller bietet eine Methode, die ein SAX ContentHandler als ein Argument verwendet. Sie können das vortäuschen ContentHandler und überprüfen, dass bestimmte Methoden mit den erwarteten Argumenten aufgerufen wurden.

Hier ist ein kleines Beispiel. Ich schrieb einen benutzerdefinierten Attributes Matcher, der nur das Vorhandensein bestimmter lokaler Attributnamen überprüft, aber die Werte (noch) nicht betrachtet. Ich hoffe, dass Sie dies hilfreich:

@Mock 
private ContentHandler handler; 

private JAXBContext context; 
private ObjectFactory factory; 
private Marshaller marshaller; 

@Before 
public void setUp() throws Exception 
{ 
    context = JAXBContext.newInstance(getClass().getPackage().getName()); 
    factory = new ObjectFactory(); 
    marshaller = context.createMarshaller(); 
} 

@Test 
public void test() throws Exception 
{ 
    final UpdateDescription description = new UpdateDescription("identifier", "version"); 
    final JAXBElement<UpdateDescription> element = factory.createUpdateDescription(description); 

    marshaller.marshal(element, handler); 

    verify(handler).startDocument(); 
    verify(handler).startElement(anyString(), eq("description"), anyString(), any(Attributes.class)); 
    verify(handler).startElement(anyString(), eq("identifier"), anyString(), attrs("value")); 
    verify(handler).startElement(anyString(), eq("version"), anyString(), attrs("value")); 
    verify(handler).endDocument(); 
} 

private static Attributes attrs(final String... localNames) 
{ 
    final Matcher<Attributes> matcher = new TypeSafeMatcher<Attributes>() 
    { 
     private Set<String> names = Sets.<String> newHashSet(localNames); 

     @Override 
     public void describeTo(final Description description) 
     { 
      // TODO Auto-generated method stub 
     } 

     @Override 
     public boolean matchesSafely(final Attributes item) 
     { 
      final Set<String> presentLocalNames = Sets.newHashSetWithExpectedSize(item.getLength()); 
      final int length = item.getLength(); 
      for (int i = 0; i < length; ++i) { 
       presentLocalNames.add(item.getLocalName(i)); 
      } 

      return Sets.difference(names, presentLocalNames).isEmpty(); 
     } 
    }; 
    return new ThreadSafeMockingProgress().getArgumentMatcherStorage().reportMatcher(matcher).returnFor(
      new AttributesImpl()); 
} 
+0

ich die Art, wie diese aussieht, aber ich kann Ihnen eher ein Beispiel nennen? –

0

eigentlich kann man erwartete Ergebnis schreiben, um zu vergleichen, was von jaxb erzeugt wird, vergessen Sie nicht, hinzuzufügen „\ n“ am Ende des erwarteten Ergebnisses, das die verursachen können Assertionsfehler

3

Für diejenigen, die einen einfacheren Test bevorzugen, ist hier, was ich zusammen in RobertB Antwort verknüpft aus der Post gestellt, und die Antworten here:

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBElement; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.namespace.QName; 
import javax.xml.transform.stream.StreamSource; 

public class JaxbTestHelper { 

    @SuppressWarnings({ "rawtypes", "unchecked" }) 
    public static Object jaxbMarshalUnmarshal(Object schemaObject) throws Exception { 
     JAXBContext context = JAXBContext.newInstance(schemaObject.getClass()); 
     Marshaller marshaller = context.createMarshaller(); 
     Unmarshaller unmarshaller = context.createUnmarshaller(); 
     ByteArrayOutputStream output = new ByteArrayOutputStream(); 
     Object unmarshalledObject = null; 

     try { 
      marshaller.marshal(schemaObject, output); 
      ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); 
      unmarshalledObject = unmarshaller.unmarshal(input); 
     } catch (JAXBException e) { 
      // object class not annotated with @XmlRootElement, so we have to "wrap" and "unwrap" the object 
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
      marshaller.marshal(new JAXBElement(new QName("uri", "local"), schemaObject.getClass(), schemaObject), 
        output); 

      StreamSource source = new StreamSource(new ByteArrayInputStream(output.toByteArray())); 
      unmarshalledObject = unmarshaller.unmarshal(source, schemaObject.getClass()).getValue(); 
     } 

     // callers should verify this returned object equals the schema object passed in 
     // ie, mySchemaObject.equals(jaxbMarshalUnmarshal(mySchemaObject)) 
     return unmarshalledObject; 
    } 

} 

3

Ich konfrontiert mit dem gleichen Problem der XML-Marshalling-Tests. Sie können XmlUnit Bibliothek verwenden, um Sie serialisierten XML mit Etalon zu vergleichen. XmlUnit kann zwei XML-Dateien vergleichen und unterstützt Features wie Ignorieren von Leerzeichen, Neuordnung von Elementen und einiges mehr.

Hier guter Artikel von IBM developer ist about XmlUnit,
obwohl heißt beschreibt ältere Version von XMLUnit, gibt es eine gute Erklärung und Beispiele.

Vergleichen xml ist wie folgt aussehen:

Diff diff = DiffBuilder 
      .compare(expectXml) 
      .withTest(marshaledXml) 
      //Ignore element order 
      .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byName)) 
      .ignoreWhitespace() 
      .ignoreComments() 
      .checkForSimilar() 
      .build() 

    assert !diff.hasDifferences()