2012-08-25 106 views
10

我正在使用Jaxb 2.0 api而不使用XSD,并使用注释创建了内容模型。我想为编组的班级编写一份Junit测试。我原来的计划是比较预期的XML字符串与实际的断言(最明显的选择)。但我发现编组创建xml属性/属性顺序不可预测(实际上我不知道什么是默认顺序)。现在,如果是这种情况,我不能假定一个预定义的XML字符串,然后将其与编组的字符串进行比较。我正在考虑声称编组类的另一种方式如下:如何为JAXB 2.0编写单元测试编组

1-创建内容模型。

2-Marshall it。

3-Unmarshall在步骤2创建的xml以获取模型。

基于模型在步骤1和步骤3对属性/属性进行断言。

但我仍然不觉得满意。在这种情况下,编写Junit测试进行编组的正确方法是什么?

虽然使用编组xml的实际应用程序不依赖于xml属性/属性顺序,但Junit测试似乎很棘手。

感谢

回答

6

我偶然发现了你的问题,而google搜索同样的事情。如果发现这个post,但不喜欢之后必须“解析”生成的XML的想法。在通过JAXB Javadoc筛选后,我发现了一个我非常喜欢的方法。 JAXB Marshaller提供了一种将SAX ContentHandler作为参数的方法。你可以嘲笑ContentHandler,并验证具体的方法已经被调用了预期的参数。

这里有一个小例子。我写了一个自定义Attributes匹配器,它只验证某些属性本地名称的存在,但不查看值(还)。我希望对您有所帮助:

@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

我喜欢的样子,但我可以提供更多的例子吗? –

0

其实你可以写预期的结果在你预料的结果结束这很可能导致要比较的是由JAXB生成了什么,不要忘记加上“\ n”断言错误

3

对于那些谁喜欢一个简单的测试,这里就是我放在一起从RobertB的答案链接后,答案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

我面临着XML编组测试的相同问题。你可以使用XmlUnit库来比较你序列化XML与标准具。 XmlUnit可以比较两个xml,并支持忽略空间,元素重新排序等功能。

这里是IBM developerWorks中国about XmlUnit
虽然介绍XMLUnit测试的老版本的好文章,它提供了很好的解释和例子。

比较XML的可能是这样的:

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

    assert !diff.hasDifferences()