项目封装了新的SDK,需要对SDK进行测试,API没有变更。

设计一自动化CASE:

  1. 通过openapi的方式调用YAPI上接口测试用例,返回结果A;
  2. 引入SDK,编写单元测试代码,通过SDK调用接口,返回结果B;
  3. 对结果(xml/Json)进行排序后断言。

因为整个环境只有SDK是新的,所以完成以上CASE,基本可以找出SDK中存在的Bug。

但是返回结果中xml和Json的属性顺序不一定相对,所以用基本的equals可能会存在判断不准确的情况,需要提前对结果进行自然排序,排序后进行比较即可。

一、Json排序

fastjson,使用SerializerFeature.MapSortField参数,可以达到目的。

@Slf4j
public class FastJsonSortTest
{
    @Test
    public void testSortJson()
    {
        String json = "";
    
        JSONObject jsonObject = JSON.parseObject(json);
        String rs = JSON.toJSONString(jsonObject, SerializerFeature.MapSortField, SerializerFeature.PrettyFormat);
        log.info("rn{}", rs);
    }
}

b284d3be4d7b54c2a01f24d30b2a756c.png

二、xml排序

xml比较复杂,这里只讨论POJO<->xml的形式。

对于比较POJO形式的xml根据node名称进行自然排序即可,使用XSLT进行sort即可。

@Slf4j
public class XmlSortTest
{
    @Test
    public void testSorXml() throws Exception
    {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer(new StreamSource("E:Mediff-xmlsrcmainresourcessort.xsl"));
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        transformer.transform(new StreamSource("E:Mediff-xmlsrcmainresources2.xml"), new StreamResult(outputStream));
        log.info("rn{}", (outputStream.toString()));
    }
}

对应的xsl文件。

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*">
                <xsl:sort select="name()"/>
            </xsl:apply-templates>

            <xsl:apply-templates select="node()">
                <xsl:sort select="name()"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

手工调整xml中结点位置,对于生成的结果文件进行比较,完全一致。

d335d4268b8bd6d4c209b843d3be0e48.png

三、XML排序 - 续

好悲剧啊,接口返回的xml信息太复杂了,以至于XSLT模板比较难配置,该方案最终折戟。这里还是把即将删除的代码记录一下。

@Scan
@Slf4j
public class SortXml
{
    @Conf("sort.xsl")
    private static String xsltFile;
    
    /**
     * 使用XSLT对xml进行排序
     */
    public static String sort(String xml)
    {
        // XSLT模板文件,放置于test目录下的resouces中
        try
        {
            InputStream xsltIn = FileUtil.getFileInputStream(xsltFile);
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer(new StreamSource(xsltIn));
            ByteArrayInputStream inputStream = new ByteArrayInputStream(xml.getBytes());
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            transformer.transform(new StreamSource(inputStream), new StreamResult(outputStream));
            return outputStream.toString();
        }
        catch (Exception e)
        {
            log.error("SortXml处理异常,{}", xml, e);
        }
        return null;
    }
}

XSLT增加结点过滤。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes" encoding="GBK"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*">
                <xsl:sort select="name()"/>
            </xsl:apply-templates>

            <xsl:apply-templates select="node()">
                <xsl:sort select="name()"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <!--过滤结点-->
    <xsl:template match="time|password"/>
</xsl:stylesheet>

四、XMLUnit

终极方案,XMLUnit,不多解释了。

https://www.xmlunit.org/

https://github.com/xmlunit/xmlunit

http://xmlunit.sourceforge.net/userguide/XMLUnit-Java.pdf

探究 XMLUnit

XMLUnit: 验证比较XML文件的工具

五、FastJson最终处理

实在是写不动了,还是贴代码了。

对于Json中也需要对部分字段进行忽略,可以使用filter进行过滤。

public class JsonCompareUtil
{
    @Conf("ignore.node.name")
    private static String ignoreNodeNameStr = "time,resultElapse,productImg";
    
    private static SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
    
    static
    {
        String[] ignoreNodeNames = JsonCompareUtil.ignoreNodeNameStr.split(",|,");
        for (String ignoreNodeName : ignoreNodeNames)
        {
            filter.getExcludes().add(ignoreNodeName);
        }
    }
    
    private static String jsonFilter(String json)
    {
        JSONObject jsonObject = JSON.parseObject(json);
        String rs = JSON.toJSONString(jsonObject, filter, SerializerFeature.MapSortField, SerializerFeature.PrettyFormat);
        return rs;
    }
    
    public static boolean compare(String jsonSource, String jsonCompareWith)
    {
        jsonSource = jsonFilter(jsonSource);
        jsonCompareWith = jsonFilter(jsonCompareWith);
        return jsonSource.equals(jsonCompareWith);
    }
}
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐