Java单元测试中序列化org.w3c.dom.Node实现高效测试可行吗?
关于org.w3c.dom.Node序列化与单元测试构造的解决方案
直接序列化org.w3c.dom.Node对象不可行——JDK自带的标准DOM实现(比如com.sun.org.apache.xerces.internal.dom.NodeImpl)大多未实现Serializable接口,强行序列化会抛出NotSerializableException。以下是两种可行的替代方案:
方案一:从日志XML字符串直接构建Node(推荐)
这是最直接高效的方式,利用JDK自带XML解析API将日志中的XML内容转为org.w3c.dom.Node:
import org.w3c.dom.Node; import org.w3c.dom.Document; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.StringReader; import org.xml.sax.InputSource; public class TestUtils { public static Node buildNodeFromXml(String xmlStr) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 若XML包含命名空间,需开启对应支持 // factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new InputSource(new StringReader(xmlStr))); // 根据日志XML结构返回对应节点: // 1. 完整XML文档返回根节点 return doc.getDocumentElement(); // 2. 目标子节点可通过标签名定位: // return doc.getElementsByTagName("target-node").item(0); } }
单元测试中直接调用该方法:
@Test public void testProcessNode() throws Exception { // 从日志复制的XML内容 String testXml = "<root><node attr='value'>content</node></root>"; Node testNode = TestUtils.buildNodeFromXml(testXml); ComponentB b = new ComponentB(); b.processNode(testNode); // 添加自定义断言逻辑 }
方案二:持久化DOM节点的替代方式
若不想每次硬编码或解析XML字符串,可通过以下方式持久化Node对象:
方式1:将Node转为XML字符串保存到资源文件
在组件B中临时添加代码,将接收到的Node转为XML字符串写入文件(测试完成后移除):
import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.FileWriter; public void processNode(Node inp) { // 临时序列化代码 try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.transform(new DOMSource(inp), new StreamResult(new FileWriter("node_input.xml"))); } catch (Exception e) { e.printStackTrace(); } // 原有业务逻辑 }
运行一次组件A调用后,将生成的node_input.xml放入测试资源目录,单元测试时读取文件内容再解析为Node:
@Test public void testProcessNodeFromFile() throws Exception { String xmlStr = new String(Files.readAllBytes(Paths.get("src/test/resources/node_input.xml"))); Node testNode = TestUtils.buildNodeFromXml(xmlStr); ComponentB b = new ComponentB(); b.processNode(testNode); }
方式2:使用第三方库序列化DOM节点
以DOM4J为例,需先添加Maven依赖:
<dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.4</version> <scope>test</scope> </dependency>
序列化代码(临时添加到组件B中):
import org.dom4j.io.DOMReader; import org.dom4j.io.XMLWriter; import java.io.FileOutputStream; public void processNode(Node inp) { try { DOMReader reader = new DOMReader(); org.dom4j.Document dom4jDoc = reader.read((org.w3c.dom.Document) inp); XMLWriter writer = new XMLWriter(new FileOutputStream("node_serialized.xml")); writer.write(dom4jDoc); writer.close(); } catch (Exception e) { e.printStackTrace(); } // 原有业务逻辑 }
反序列化代码(单元测试中):
import org.dom4j.io.SAXReader; import org.dom4j.io.DOMWriter; @Test public void testProcessNodeWithDom4j() throws Exception { SAXReader saxReader = new SAXReader(); org.dom4j.Document dom4jDoc = saxReader.read(new File("src/test/resources/node_serialized.xml")); DOMWriter domWriter = new DOMWriter(); org.w3c.dom.Document w3cDoc = domWriter.write(dom4jDoc); Node testNode = w3cDoc.getDocumentElement(); ComponentB b = new ComponentB(); b.processNode(testNode); }
内容的提问来源于stack exchange,提问作者tarekahf
相关产品推荐
相关产品推荐

