《软件测试自动化之道》读书笔记 之 XML测试

《软件测试自动化之道》读书笔记 之 XML测试

2014-10-07

待测程序
测试程序
  通过XmlTextReader解析XML
  通过XmlDocument解析XML
  通过XmlPathDocument解析XML
  通过XmlSerializer解析XML
  通过DataSet解析XML
  通过XSD Schema对XML文件进行验证
  通过XSLT对XML文件进行修改
  通过XmlTextWrite对XML文件进行写操作
  比较两个XML文件是否严格相等
  不考虑编码方式,比较两个XML文件是否严格相等
  比较两个XML文件的规范等价性
  示例代码

待测程序



 返回

‘testCases.xml’示例代码:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <suite>
 3   <testcase id="001" bvt="yes">
 4     <inputs>
 5       <arg1>red</arg1>
 6       <arg2>blue</arg2>
 7     </inputs>
 8     <expected>purple</expected>
 9   </testcase>
10
11   <testcase id="002" bvt="no">
12     <inputs>
13       <arg1>blue</arg1>
14       <arg2>yellow</arg2>
15     </inputs>
16     <expected>green</expected>
17   </testcase>
18
19   <testcase id="003" bvt="yes">
20     <inputs>
21       <arg1>white</arg1>
22       <arg2>black</arg2>
23     </inputs>
24     <expected>gray</expected>
25   </testcase>
26 </suite>

测试程序



 返回

本章给出5种解析技术,都是把‘testCases.xml’解析成测试用例Suite对象,Suite的定义如下:

 1 namespace Utility
 2 {
 3     public class TestCase
 4     {
 5         public string id;
 6         public string bvt;
 7         public string arg1;
 8         public string arg2;
 9         public string expected;
10     }
11
12     public class Suite
13     {
14         public System.Collections.ArrayList cases = new System.Collections.ArrayList();
15         public void Display()
16         {
17             foreach (TestCase tc in cases)
18             {
19                 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.arg1 + " " + tc.arg2 + " " + tc.expected);
20             }
21         }
22     }
23 }

通过XmlTextReader解析XML

示例代码:

 1         private static void ParseByXMLTextReader(Utility.Suite suite, string tcPath)
 2         {
 3             XmlTextReader xtr = new XmlTextReader(tcPath);
 4             xtr.WhitespaceHandling = WhitespaceHandling.None;
 5             xtr.Read(); //read xml declaration, move to tag<suite>
 6
 7             while (!xtr.EOF)
 8             {
 9                 if (xtr.Name == "suite" && !xtr.IsStartElement()) break;
10                 while (xtr.Name != "testcase" || !xtr.IsStartElement())
11                     xtr.Read(); //move to tag<testcase>
12
13                 Utility.TestCase tc = new Utility.TestCase();
14                 tc.id = xtr.GetAttribute("id");
15                 tc.bvt = xtr.GetAttribute("bvt");
16                 xtr.Read(); //move to tag <inputs>
17                 xtr.Read(); //move to tag <arg1>
18                 tc.arg1 = xtr.ReadElementString("arg1");
19                 tc.arg2 = xtr.ReadElementString("arg2");
20                 xtr.Read(); //move to tag <expected>
21                 tc.expected = xtr.ReadElementString("expected");
22                 //current tag is </testcase>
23                 suite.cases.Add(tc);
24
25                 xtr.Read(); //current tag is <testcase> or </suite>
26             }
27             xtr.Close();
28         }
29     }

分析:

XmlTextReader把XML 解析成单个的数据片,如下xml:

<?xml version="1.0" encoding="utf-8" ?>
<alpha id="001">
  <beta>123</beta>
</alpha>

不计空格,这里共有6个结点:XML声明、<alpha id="001">、<beta>、123、</beta>、</alpha>。

  • Read()方法:每次向前读取一个结点。与其它类的Read()不同,该方法并不返回有意义的数据;
  • ReadElementString()方法:才会返回单个标签和结尾之间的数据,并向前糯稻标签结束后面的下一个结点。
  • EOF属性:判断是否碰到文件结尾

当被解析的XML文件结构相对比较简单并且前后一致,且需要向前进行处理的时候,使用XmlTextReader是 一种直接有效的方法。与本章其他解析技术相比,也是最快的方法。与本章其他解析技术相比,XmlTextReader所进行的操作在比较地的抽象层次上,也就以为这作为程序员,要负责正确跟踪XML文件中的位置和正确调用Read()。

通过XmlDocument解析XML

示例代码:

 1         private static void ParseByXMLDocument(Utility.Suite suite, string tcPath)
 2         {
 3             XmlDocument xd = new XmlDocument();
 4             xd.Load(tcPath);
 5
 6             //get all <testcase> nodes
 7             XmlNodeList nodeList = xd.SelectNodes("/suite/testcase");
 8             foreach (XmlNode node in nodeList)
 9             {
10                 Utility.TestCase tc = new Utility.TestCase();
11                 tc.id = node.Attributes.GetNamedItem("id").Value;
12                 tc.bvt = node.Attributes.GetNamedItem("bvt").Value;
13
14                 XmlNode n = node.SelectSingleNode("inputs");
15                 tc.arg1 = n.ChildNodes.Item(0).InnerText;
16                 tc.arg2 = n.ChildNodes.Item(1).InnerText;
17                 tc.expected = node.ChildNodes.Item(1).InnerText;
18
19                 suite.cases.Add(tc);
20             }
21         }

分析:

XmlDocument.Load()方法:把整个XML文件读如内存中。XmlDocument对象基于XML结点和子结点的概念。我们不采用顺序的方式遍历XML文件,而是通过SelectNodes()方法选择一组结点,或这通过SelectSingleNode()选择单个的结点。请注意:因为XML文件的attributes和elements之间有着显著的差别,所以我们必须通过Attributes.GetNamedItem()方法得到某个元素结点的id和bvt值。

因为XmlDocument会一次把整个XML文挡读入到内存中,所以对于被解析的XML文件非常大的情况,这种方法并不合适。

通过XmlPathDocument解析XML

示例代码:

 1         private static void ParseByXPathDocument(Utility.Suite suite, string tcPath)
 2         {
 3             System.Xml.XPath.XPathDocument xpd = new XPathDocument(tcPath);
 4             XPathNavigator xpn = xpd.CreateNavigator();
 5             XPathNodeIterator xpi = xpn.Select("/suite/testcase");
 6
 7             while (xpi.MoveNext())
 8             {
 9                 Utility.TestCase tc = new Utility.TestCase();
10                 tc.id = xpi.Current.GetAttribute("id", xpn.NamespaceURI);
11                 tc.bvt = xpi.Current.GetAttribute("bvt", xpn.NamespaceURI);
12
13                 XPathNodeIterator tcChild = xpi.Current.SelectChildren(XPathNodeType.Element);
14                 while (tcChild.MoveNext())
15                 {
16
17                         if (tcChild.Current.Name == "inputs")
18                         {
19                             XPathNodeIterator tcSubChild = tcChild.Current.SelectChildren(XPathNodeType.Element);
20                             while (tcSubChild.MoveNext())
21                             {
22                                 if (tcSubChild.Current.Name == "arg1")
23                                     tc.arg1 = tcSubChild.Current.Value;
24                                 else if (tcSubChild.Current.Name == "arg2")
25                                     tc.arg2 = tcSubChild.Current.Value;
26                             }
27                         }
28                         else if (tcChild.Current.Name == "expected")
29                             tc.expected = tcChild.Current.Value;
30
31                 }
32                 suite.cases.Add(tc);
33             }
34         }

分析:

  • XpathDocument()构造函数:把整个XML文件存入内存。
  • XpathNavigator对象的Select()方法:选择XML文挡的一部分
  • XpathNodeIterator对象的MoveNext()方法:遍历XpathDocument对象。
  • GetAttribut()方法:取得attribute的值
  • SelectChildren()方法和Current.Value属性:取得XML元素的值

通过XmlPathDocument对象对XML文件进行解析,给人的感觉是它一部分是过程式的、底层的(类似于XmlTextReader)处理方法,一部分是面向对象的、高层次的(类似于XMLDocument)的处理方法。

XmlPathDocument类是针对XPath数据模型特别优化过的。所以当要解析的XML文件嵌套层次很深、结构很复杂或者需要大范围的查找炒作,这种方法尤为合适。但XmlPathDocument只能对XML文件进行读取,所以如果想对文件在内存中进行直接的操作,这种方法不行。

通过XmlSerializer解析XML

示例代码:

内存结构对应类:

 1 namespace SerializerLib
 2 {
 3     using System.Xml.Serialization;
 4
 5     [XmlRootAttribute("suite")]
 6     public class Suite
 7     {
 8         [XmlElementAttribute("testcase")]
 9         public TestCase[] items;
10         public void Display()
11         {
12             foreach(TestCase tc in items)
13             {
14                 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.inputs.arg1 + " " + tc.inputs.arg2 + " " + tc.expected);
15             }
16         }
17
18     }
19
20     public class TestCase
21     {
22         [XmlAttributeAttribute()]
23         public string id;
24         [XmlAttributeAttribute()]
25         public string bvt;
26         [XmlElementAttribute("inputs")]
27         public Inputs inputs;
28         public string expected;
29
30     }
31
32     public class Inputs
33     {
34         public string arg1;
35         public string arg2;
36     }
37 }

ParseByXmlSerializer()方法:

1         private static void ParseByXmlSerializer(string tcPath)
2         {
3             XmlSerializer xs = new XmlSerializer(typeof(SerializerLib.Suite));
4             StreamReader sr = new StreamReader(tcPath);
5             SerializerLib.Suite suite = (SerializerLib.Suite)xs.Deserialize(sr);
6             sr.Close();
7             suite.Display();
8         }

分析:

通过XmlSerializer类对XML文件进行解析于其他5中XML解析类有着很大的不同,因为采用这种方法必须很仔细的把存储结构预先准备好。我们注意到把XML加载到内存中的操作只通过下面一个语句就完成了:

SerializerLib.Suite suite = (SerializerLib.Suite)xs.Deserialize(sr);

存储结构可以手工编写一个目标类,也可以通过Visual Studio .NET自带的xsd.exe命令行工具:

首先,执行以下命令(假设testCase.xml位于C盘根目录):

C:\>xsd.exe testCases.xml /o:.

这个命令的意思上创建testCases.xml文件的XSD schema定义并且把结果按照默认名保存到当前目录

然后,执行以下命令:

C:\xsd.exe testCases.xsd /c /o:.

这个命令的意思是使用testCase.xsd定义文件,通过默认的C#语言产生一组于Deserialize()方法兼容的类,并且以默认文件名testCases.cs保存到当前目录。

现在你可以把testCases.cs的代码直接拷贝到测试套间中,稍加修改(比如:去处一些不需要的代码,加一些额外的方法,改名等)

XmlSerialzier类为XML文件的解析提供了一种非常优雅的解决方案。所进行的操作也在最高的抽象层次,也就是说算法的细节大多屏蔽掉了。但也失去了一些对XML处理过程的处理。

通过DataSet解析XML

示例代码:

 1         private static void ParseByDataSet(Utility.Suite suite, string tcPath)
 2         {
 3             DataSet ds = new DataSet();
 4             ds.ReadXml(tcPath);
 5
 6             foreach (DataRow row in ds.Tables["testcase"].Rows)
 7             {
 8                 Utility.TestCase tc=new Utility.TestCase();
 9                 tc.id = row["id"].ToString();
10                 tc.bvt = row["bvt"].ToString();
11                 tc.expected = row["expected"].ToString();
12
13                 DataRow[] children = row.GetChildRows("testcase_inputs"); //relation name
14                 tc.arg1=(children[0]["arg1"]).ToString();
15                 tc.arg2=(children[0]["arg2"]).ToString();
16
17                 suite.cases.Add(tc);
18             }
19         }

分析:

ReadXml()方法:把XML文件直接读如一个System.Data.DataSet对象。你可以把DataSet对象想像成一个内存中的关系型数据库。通过DataSet对象对XML进行解析,关键是要理解XML(本质上是层次型的)是如何映射到一组DataTable对象(本质上是平面型的)的。XML源文件的每个层次都会在DataSet中产生一个表。

顶层的<testcase>产生一个名为testcase的DataTable。下一层次<inputs>产生一个名为inputs的DataTable。这时候还会产生一个叫做testcase_inputs的关系对象用来连接DataTable对象。请注意:XML的根结点所在的层次和最低层(本例中即<arg>所表示的数据)并不会产生表。

下面这个‘DisplayInfo’方法的代码提供一些你需要的信息:

 1         public static void DisplayInfo(DataSet ds)
 2         {
 3             foreach (DataTable dt in ds.Tables)
 4             {
 5                 Console.WriteLine("\n==========================================");
 6                 Console.WriteLine("Table= " + dt.TableName + "\n");
 7                 foreach (DataColumn dc in dt.Columns)
 8                     Console.Write("{0,-14}", dc.ColumnName);
 9                 Console.WriteLine("\n------------------------------------------");
10                 foreach (DataRow dr in dt.Rows)
11                 {
12                     foreach(object data in dr.ItemArray)
13                         Console.Write("{0,-14}", data.ToString());
14                     Console.WriteLine();
15                 }
16                 Console.WriteLine("\n==========================================");
17             }
18             foreach (DataRelation dr in ds.Relations)
19             {
20                 Console.WriteLine("\n\nRelations:");
21                 Console.WriteLine(dr.RelationName+"\n\n");
22             }
23         }

图1 DataSet信息

通过XSD Schema对XML文件进行验证

示例代码:

 1         private static void VerifyByXsdSchema(string tcPath)
 2         {
 3             XmlSchemaCollection xsc = new XmlSchemaCollection();
 4             xsc.Add(null, @"..\..\testCases.xsd");
 5             XmlTextReader xtr = new XmlTextReader(tcPath);
 6             XmlValidatingReader xvr = new XmlValidatingReader(xtr);
 7             xvr.ValidationType = ValidationType.Schema;
 8             xvr.Schemas.Add(xsc);
 9             xvr.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
10             while (xvr.Read()) ;
11
12             Console.WriteLine("If no error message then XML is valid");
13         }

分析:

通过XmlValidatingReader对象对想要验证的XML文件进行遍历。如果这个文件不是有效的XML文件,程序控制流程转向一个代理方法(delegate method),这个代理方法会打印出错误信息。

通过XmlSchemaCollection对象加载用于验证的schema定义,通过这种方法可以针对XML文件应用多个schema定义。

通过XSLT对XML文件进行修改

‘testCase.xml’原始形式如下:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <suite>
 3   <testcase id="001" bvt="yes">
 4     <inputs>
 5       <arg1>red</arg1>
 6       <arg2>blue</arg2>
 7     </inputs>
 8     <expected>purple</expected>
 9   </testcase>
10
11 <suite>

修改后的版本:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <allOfTheTestCases>
 3   <aCase caseID="001">
 4     <bvt>yes</bvt>
 5     <expRes>purple</expRes>
 6     <inputs>
 7       <input1>red</input1>
 8       <input2>blue</input2>
 9     </inputs>
10   </aCase>
11
12 </allOfTheTestCases>

示例代码:

‘testCasesModifier.xslt’代码:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 3     xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
 4 >
 5     <xsl:output method="xml" indent="yes"/>
 6
 7     <xsl:template match="/">
 8       <allOfTheTestCases>
 9         <xsl:for-each select ="//testcase">
10           <aCase>
11             <xsl:attribute name="caseID">
12               <xsl:value-of select ="@id"/>
13             </xsl:attribute>
14             <bvt>
15               <xsl:value-of select="@bvt"/>
16             </bvt>
17             <expRes>
18               <xsl:value-of select="expected"/>
19             </expRes>
20             <inputs>
21               <xsl:for-each select="inputs">
22                 <input1>
23                   <xsl:value-of select="arg1"/>
24                 </input1>
25                 <input2>
26                   <xsl:value-of select="arg2"/>
27                 </input2>
28               </xsl:for-each>
29             </inputs>
30           </aCase>
31         </xsl:for-each>
32       </allOfTheTestCases>
33     </xsl:template>
34 </xsl:stylesheet>

UpdateXMLByXSLT()方法代码:

1         private static void UpdateXMLByXSLT(string tcPath)
2         {
3             XslTransform xst = new XslTransform();
4             xst.Load(@"..\..\testCasesModifier.xslt");
5             xst.Transform(tcPath, @"..\..\testCasesModifier.xml");
6             Console.WriteLine("Done. New XML file is ‘testCasesModifier.xml‘");
7         }

通过XmlTextWrite对XML文件进行写操作

示例代码:

 1         private static void WriteXMLbyXmlTextWrite()
 2         {
 3             string caseID = "0001";
 4             string result = "Pass";
 5             string whenRun = "10/09/2014";
 6             XmlTextWriter xtw = new XmlTextWriter(@"..\..\Results1.xml", System.Text.Encoding.UTF8);
 7             xtw.Formatting = Formatting.Indented;
 8             xtw.WriteStartDocument();
 9             xtw.WriteStartElement("Results");
10             xtw.WriteStartElement("result");
11             xtw.WriteAttributeString("id", caseID);
12             xtw.WriteStartElement("passfaill");
13             xtw.WriteString(result);
14             xtw.WriteEndElement();
15             xtw.WriteStartElement("whenRun");
16             xtw.WriteString(whenRun);
17             xtw.WriteEndElement();
18             xtw.WriteEndElement();
19             xtw.WriteEndElement();
20             xtw.Close();
21         }

结果‘TestResult1.xml’:

1 <?xml version="1.0" encoding="utf-8"?>
2 <Results>
3   <result id="0001">
4     <passfaill>Pass</passfaill>
5     <whenRun>10/09/2014</whenRun>
6   </result>
7 </Results>

比较两个XML文件是否严格相等

示例代码:

 1         private static bool XMLExactlySame(string file1,string file2)
 2         {
 3             FileStream fs1 = new FileStream(file1, FileMode.Open);
 4             FileStream fs2 = new FileStream(file2, FileMode.Open);
 5
 6             if (fs1.Length != fs2.Length)
 7                 return false;
 8             else
 9             {
10                 int b1 = 0;
11                 int b2 = 0;
12
13                 while ((b1 = fs1.ReadByte()) != -1)
14                 {
15                     b2 = fs2.ReadByte();
16                     if (b1 != b2)
17                     {
18                         fs1.Close();
19                         fs2.Close();
20                         return false;
21                     }
22                 }
23                 fs1.Close();
24                 fs2.Close();
25                 return true;
26             }
27         }

分析:

通过FileStream对象遍历两个XML文件。一个字节一个字节的读入文件内容,如果某个字节不匹配,则返回false。

不考虑编码方式,比较两个XML文件是否严格相等

示例代码:

 1         private static bool XMLExactlyExceptEncoding(string file1, string file2)
 2         {
 3             FileStream fs1 = new FileStream(file1, FileMode.Open);
 4             FileStream fs2 = new FileStream(file2, FileMode.Open);
 5             StreamReader sr1 = new StreamReader(fs1);
 6             StreamReader sr2 = new StreamReader(fs2);
 7
 8             string s1 = sr1.ReadToEnd();
 9             string s2 = sr2.ReadToEnd();
10             sr1.Close();
11             sr2.Close();
12             fs1.Close();
13             fs2.Close();
14             return (s1==s2);
15         }

分析:

编写软件测试时,可能需要对实际的XML文件和期望的XML文件进行比较,而不关心它们的编码机制是否一样。换句话说,如果实际的XML文件和期望的XML文件包含相同的字符数据,只不过编码方式不同(比如:UTF-8,ANSI )。若要考虑编码,可用重载过的==运算符。

比较两个XML文件的规范等价性

第一个XML文件Books1.xml代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <books>
 3
 4   <book>
 5     <title isbn=‘1111‘ storeid="A1A1">
 6       All About Apples
 7     </title>
 8     <author>
 9       <last>Anderson</last>
10       <first>Adam</first>
11     </author>
12   </book>
13 </books>

第二个XML文件Books2.xml代码如下:

 1 <books>
 2   <book>
 3     <title storeid="A1A1" isbn="1111">
 4       All About Apples
 5     </title>
 6     <author>
 7       <last>Anderson</last>
 8       <first>Adam</first>
 9     </author>
10   </book>
11 </books>

示例代码:

 1         private static void XMLCanonicalEquivalence()
 2         {
 3             string file1 = @"..\..\Books1.xml";
 4             string file2 = @"..\..\Books2.xml";
 5
 6             XmlDocument xd1 = new XmlDocument();
 7             xd1.Load(file1);
 8
 9             XmlDsigC14NTransform t1 = new XmlDsigC14NTransform(true); //true mean inclue comment
10
11             t1.LoadInput(xd1);
12             Stream s1 = t1.GetOutput() as Stream;
13             XmlTextReader xtr1 = new XmlTextReader(s1);
14             MemoryStream ms1 = new MemoryStream();
15             XmlTextWriter xtw1 = new XmlTextWriter(ms1, System.Text.Encoding.UTF8);
16             xtw1.WriteNode(xtr1, false); //false mean not copy default properties
17
18             xtw1.Flush();
19             ms1.Position = 0;
20             StreamReader sr1 = new StreamReader(ms1);
21             string str1 = sr1.ReadToEnd();
22             Console.WriteLine(str1);
23
24             Console.WriteLine("\n==============\n");
25
26             XmlDocument xd2 = new XmlDocument();
27             xd2.Load(file2);
28
29             XmlDsigC14NTransform t2 = new XmlDsigC14NTransform(true); //true mean inclue comment
30
31             t2.LoadInput(xd2);
32             Stream s2 = t2.GetOutput() as Stream;
33             XmlTextReader xtr2 = new XmlTextReader(s2);
34             MemoryStream ms2 = new MemoryStream();
35             XmlTextWriter xtw2 = new XmlTextWriter(ms2, System.Text.Encoding.UTF8);
36             xtw2.WriteNode(xtr2, false); //false mean not copy default properties
37
38             xtw2.Flush();
39             ms2.Position = 0;
40             StreamReader sr2 = new StreamReader(ms2);
41             string str2 = sr2.ReadToEnd();
42             Console.WriteLine(str2);
43
44             if (str1 == str2)
45                 Console.WriteLine("Files cannonically equivalent");
46             else
47                 Console.WriteLine("Files Not canonically equivalent");
48         }

分析:

通过XmlDsigC14NTransform类对两个要比较的XML文件实施C14N规范花转换,然后通过两个MemoryStream对象对内存中两个转换后文件进行比较。你可以把规范等价性想像成“从大多数实际应用的角度来看都是相等的”。

上面两个XML文件‘Books1.xml’,‘Bools2.xml’具有规范等价性。两个文件中的空格不影响比较的结果;但引号双引号不影响比较的结果;XML声明不影响比较的结果;attributes的顺序不影响比较的结果。

C14N规范等价性是相当复杂的。它是有W3C定义的,主要用于安全领域,XmlDsigC14NTransform类位于System.Security.dll中。为了判断一个XML文件在网络传输的过程中是否被无意中修改或被恶意修改,我们可以比较发送文件和接受文件加密哈希值。但是,由于网络可能会修改这个文件,我们需要以某种方式来判断它们的规范等价性。

示例代码

  1 using System;
  2 using System.Text;
  3
  4 using System.Xml;
  5 using System.Xml.XPath;
  6
  7 using System.Xml.Serialization;
  8 using System.IO;
  9 using System.Data;
 10 using System.Xml.Schema;
 11 using System.Xml.Xsl;
 12
 13 using System.Security.Cryptography.Xml;
 14
 15 namespace XMLTest
 16 {
 17     class Program
 18     {
 19         static void Main(string[] args)
 20         {
 21             Console.WriteLine("Start\n");
 22             string tcPath = @"..\..\testCases.xml";
 23             //Utility.Suite suite = new Utility.Suite();
 24
 25             //ParseByXMLTextReader(suite, tcPath);
 26             //ParseByXMLDocument(suite, tcPath);
 27             //ParseByXPathDocument(suite, tcPath);
 28             //ParseByXmlSerializer(suite, tcPath);
 29             //ParseByDataSet(suite, tcPath);
 30
 31             //suite.Display();
 32
 33             //VerifyByXsdSchema(tcPath);
 34             //UpdateXMLByXSLT(tcPath);
 35             //WriteXMLbyXmlTextWrite();
 36
 37             //XMLExactlySame
 38             //XMLExactlyExceptEncoding
 39             XMLCanonicalEquivalence();
 40
 41             Console.WriteLine("\nDone");
 42             Console.Read();
 43         }
 44
 45         private static void XMLCanonicalEquivalence()
 46         {
 47             string file1 = @"..\..\Books1.xml";
 48             string file2 = @"..\..\Books2.xml";
 49
 50             XmlDocument xd1 = new XmlDocument();
 51             xd1.Load(file1);
 52
 53             XmlDsigC14NTransform t1 = new XmlDsigC14NTransform(true); //true mean inclue comment
 54
 55             t1.LoadInput(xd1);
 56             Stream s1 = t1.GetOutput() as Stream;
 57             XmlTextReader xtr1 = new XmlTextReader(s1);
 58             MemoryStream ms1 = new MemoryStream();
 59             XmlTextWriter xtw1 = new XmlTextWriter(ms1, System.Text.Encoding.UTF8);
 60             xtw1.WriteNode(xtr1, false); //false mean not copy default properties
 61
 62             xtw1.Flush();
 63             ms1.Position = 0;
 64             StreamReader sr1 = new StreamReader(ms1);
 65             string str1 = sr1.ReadToEnd();
 66             Console.WriteLine(str1);
 67
 68             Console.WriteLine("\n==============\n");
 69
 70             XmlDocument xd2 = new XmlDocument();
 71             xd2.Load(file2);
 72
 73             XmlDsigC14NTransform t2 = new XmlDsigC14NTransform(true); //true mean inclue comment
 74
 75             t2.LoadInput(xd2);
 76             Stream s2 = t2.GetOutput() as Stream;
 77             XmlTextReader xtr2 = new XmlTextReader(s2);
 78             MemoryStream ms2 = new MemoryStream();
 79             XmlTextWriter xtw2 = new XmlTextWriter(ms2, System.Text.Encoding.UTF8);
 80             xtw2.WriteNode(xtr2, false); //false mean not copy default properties
 81
 82             xtw2.Flush();
 83             ms2.Position = 0;
 84             StreamReader sr2 = new StreamReader(ms2);
 85             string str2 = sr2.ReadToEnd();
 86             Console.WriteLine(str2);
 87
 88             if (str1 == str2)
 89                 Console.WriteLine("Files cannonically equivalent");
 90             else
 91                 Console.WriteLine("Files Not canonically equivalent");
 92         }
 93
 94         private static bool XMLExactlyExceptEncoding(string file1, string file2)
 95         {
 96             FileStream fs1 = new FileStream(file1, FileMode.Open);
 97             FileStream fs2 = new FileStream(file2, FileMode.Open);
 98             StreamReader sr1 = new StreamReader(fs1);
 99             StreamReader sr2 = new StreamReader(fs2);
100
101             string s1 = sr1.ReadToEnd();
102             string s2 = sr2.ReadToEnd();
103             sr1.Close();
104             sr2.Close();
105             fs1.Close();
106             fs2.Close();
107             return (s1==s2);
108         }
109
110         private static bool XMLExactlySame(string file1,string file2)
111         {
112             FileStream fs1 = new FileStream(file1, FileMode.Open);
113             FileStream fs2 = new FileStream(file2, FileMode.Open);
114
115             if (fs1.Length != fs2.Length)
116                 return false;
117             else
118             {
119                 int b1 = 0;
120                 int b2 = 0;
121
122                 while ((b1 = fs1.ReadByte()) != -1)
123                 {
124                     b2 = fs2.ReadByte();
125                     if (b1 != b2)
126                     {
127                         fs1.Close();
128                         fs2.Close();
129                         return false;
130                     }
131                 }
132                 fs1.Close();
133                 fs2.Close();
134                 return true;
135             }
136         }
137
138         private static void WriteXMLbyXmlTextWrite()
139         {
140             string caseID = "0001";
141             string result = "Pass";
142             string whenRun = "10/09/2014";
143             XmlTextWriter xtw = new XmlTextWriter(@"..\..\Results1.xml", System.Text.Encoding.UTF8);
144             xtw.Formatting = Formatting.Indented;
145             xtw.WriteStartDocument();
146             xtw.WriteStartElement("Results");
147             xtw.WriteStartElement("result");
148             xtw.WriteAttributeString("id", caseID);
149             xtw.WriteStartElement("passfaill");
150             xtw.WriteString(result);
151             xtw.WriteEndElement();
152             xtw.WriteStartElement("whenRun");
153             xtw.WriteString(whenRun);
154             xtw.WriteEndElement();
155             xtw.WriteEndElement();
156             xtw.WriteEndElement();
157             xtw.Close();
158         }
159
160         private static void UpdateXMLByXSLT(string tcPath)
161         {
162             XslTransform xst = new XslTransform();
163             xst.Load(@"..\..\testCasesModifier.xslt");
164             xst.Transform(tcPath, @"..\..\testCasesModifier.xml");
165             Console.WriteLine("Done. New XML file is ‘testCasesModifier.xml‘");
166         }
167
168         private static void VerifyByXsdSchema(string tcPath)
169         {
170             XmlSchemaCollection xsc = new XmlSchemaCollection();
171             xsc.Add(null, @"..\..\testCases.xsd");
172             XmlTextReader xtr = new XmlTextReader(tcPath);
173             XmlValidatingReader xvr = new XmlValidatingReader(xtr);
174             xvr.ValidationType = ValidationType.Schema;
175             xvr.Schemas.Add(xsc);
176             xvr.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
177             while (xvr.Read()) ;
178
179             Console.WriteLine("If no error message then XML is valid");
180         }
181
182         private static void ValidationCallBack(object sender, ValidationEventArgs ea)
183         {
184             Console.WriteLine("Validation error: " + ea.Message);
185             Console.ReadLine();
186         }
187
188         public static void DisplayInfo(DataSet ds)
189         {
190             foreach (DataTable dt in ds.Tables)
191             {
192                 Console.WriteLine("\n==========================================");
193                 Console.WriteLine("Table= " + dt.TableName + "\n");
194                 foreach (DataColumn dc in dt.Columns)
195                     Console.Write("{0,-14}", dc.ColumnName);
196                 Console.WriteLine("\n------------------------------------------");
197                 foreach (DataRow dr in dt.Rows)
198                 {
199                     foreach(object data in dr.ItemArray)
200                         Console.Write("{0,-14}", data.ToString());
201                     Console.WriteLine();
202                 }
203                 Console.WriteLine("\n==========================================");
204             }
205             foreach (DataRelation dr in ds.Relations)
206             {
207                 Console.WriteLine("\n\nRelations:");
208                 Console.WriteLine(dr.RelationName+"\n\n");
209             }
210         }
211
212         private static void ParseByDataSet(Utility.Suite suite, string tcPath)
213         {
214             DataSet ds = new DataSet();
215             ds.ReadXml(tcPath);
216
217             foreach (DataRow row in ds.Tables["testcase"].Rows)
218             {
219                 Utility.TestCase tc=new Utility.TestCase();
220                 tc.id = row["id"].ToString();
221                 tc.bvt = row["bvt"].ToString();
222                 tc.expected = row["expected"].ToString();
223
224                 DataRow[] children = row.GetChildRows("testcase_inputs"); //relation name
225                 tc.arg1=(children[0]["arg1"]).ToString();
226                 tc.arg2=(children[0]["arg2"]).ToString();
227
228                 suite.cases.Add(tc);
229             }
230             DisplayInfo(ds);
231         }
232
233         private static void ParseByXmlSerializer(string tcPath)
234         {
235             XmlSerializer xs = new XmlSerializer(typeof(SerializerLib.Suite));
236             StreamReader sr = new StreamReader(tcPath);
237             SerializerLib.Suite suite = (SerializerLib.Suite)xs.Deserialize(sr);
238             sr.Close();
239             suite.Display();
240         }
241
242         private static void ParseByXPathDocument(Utility.Suite suite, string tcPath)
243         {
244             System.Xml.XPath.XPathDocument xpd = new XPathDocument(tcPath);
245             XPathNavigator xpn = xpd.CreateNavigator();
246             XPathNodeIterator xpi = xpn.Select("/suite/testcase");
247
248             while (xpi.MoveNext())
249             {
250                 Utility.TestCase tc = new Utility.TestCase();
251                 tc.id = xpi.Current.GetAttribute("id", xpn.NamespaceURI);
252                 tc.bvt = xpi.Current.GetAttribute("bvt", xpn.NamespaceURI);
253
254                 XPathNodeIterator tcChild = xpi.Current.SelectChildren(XPathNodeType.Element);
255                 while (tcChild.MoveNext())
256                 {
257
258                         if (tcChild.Current.Name == "inputs")
259                         {
260                             XPathNodeIterator tcSubChild = tcChild.Current.SelectChildren(XPathNodeType.Element);
261                             while (tcSubChild.MoveNext())
262                             {
263                                 if (tcSubChild.Current.Name == "arg1")
264                                     tc.arg1 = tcSubChild.Current.Value;
265                                 else if (tcSubChild.Current.Name == "arg2")
266                                     tc.arg2 = tcSubChild.Current.Value;
267                             }
268                         }
269                         else if (tcChild.Current.Name == "expected")
270                             tc.expected = tcChild.Current.Value;
271
272                 }
273                 suite.cases.Add(tc);
274             }
275         }
276
277         private static void ParseByXMLDocument(Utility.Suite suite, string tcPath)
278         {
279             XmlDocument xd = new XmlDocument();
280             xd.Load(tcPath);
281
282             //get all <testcase> nodes
283             XmlNodeList nodeList = xd.SelectNodes("/suite/testcase");
284             foreach (XmlNode node in nodeList)
285             {
286                 Utility.TestCase tc = new Utility.TestCase();
287                 tc.id = node.Attributes.GetNamedItem("id").Value;
288                 tc.bvt = node.Attributes.GetNamedItem("bvt").Value;
289
290                 XmlNode n = node.SelectSingleNode("inputs");
291                 tc.arg1 = n.ChildNodes.Item(0).InnerText;
292                 tc.arg2 = n.ChildNodes.Item(1).InnerText;
293                 tc.expected = node.ChildNodes.Item(1).InnerText;
294
295                 suite.cases.Add(tc);
296             }
297         }
298
299         private static void ParseByXMLTextReader(Utility.Suite suite, string tcPath)
300         {
301             XmlTextReader xtr = new XmlTextReader(tcPath);
302             xtr.WhitespaceHandling = WhitespaceHandling.None;
303             xtr.Read(); //read xml declaration, move to tag<suite>
304
305             while (!xtr.EOF)
306             {
307                 if (xtr.Name == "suite" && !xtr.IsStartElement()) break;
308                 while (xtr.Name != "testcase" || !xtr.IsStartElement())
309                     xtr.Read(); //move to tag<testcase>
310
311                 Utility.TestCase tc = new Utility.TestCase();
312                 tc.id = xtr.GetAttribute("id");
313                 tc.bvt = xtr.GetAttribute("bvt");
314                 xtr.Read(); //move to tag <inputs>
315                 xtr.Read(); //move to tag <arg1>
316                 tc.arg1 = xtr.ReadElementString("arg1");
317                 tc.arg2 = xtr.ReadElementString("arg2");
318                 xtr.Read(); //move to tag <expected>
319                 tc.expected = xtr.ReadElementString("expected");
320                 //current tag is </testcase>
321                 suite.cases.Add(tc);
322
323                 xtr.Read(); //current tag is <testcase> or </suite>
324             }
325             xtr.Close();
326         }
327     }
328 }
329
330 namespace SerializerLib
331 {
332     using System.Xml.Serialization;
333
334     [XmlRootAttribute("suite")]
335     public class Suite
336     {
337         [XmlElementAttribute("testcase")]
338         public TestCase[] items;
339         public void Display()
340         {
341             foreach(TestCase tc in items)
342             {
343                 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.inputs.arg1 + " " + tc.inputs.arg2 + " " + tc.expected);
344             }
345         }
346
347     }
348
349     public class TestCase
350     {
351         [XmlAttributeAttribute()]
352         public string id;
353         [XmlAttributeAttribute()]
354         public string bvt;
355         [XmlElementAttribute("inputs")]
356         public Inputs inputs;
357         public string expected;
358
359     }
360
361     public class Inputs
362     {
363         public string arg1;
364         public string arg2;
365     }
366 }
367
368 namespace Utility
369 {
370     public class TestCase
371     {
372         public string id;
373         public string bvt;
374         public string arg1;
375         public string arg2;
376         public string expected;
377     }
378
379     public class Suite
380     {
381         public System.Collections.ArrayList cases = new System.Collections.ArrayList();
382         public void Display()
383         {
384             foreach (TestCase tc in cases)
385             {
386                 Console.WriteLine(tc.id + " " + tc.bvt + " " + tc.arg1 + " " + tc.arg2 + " " + tc.expected);
387             }
388         }
389     }
390 }

时间: 2024-10-01 20:03:27

《软件测试自动化之道》读书笔记 之 XML测试的相关文章

《软件测试自动化之道》读书笔记 之 目录导航

<软件测试自动化之道>读书笔记 之 目录导航 2014-10-09 源代码 第1章 API测试第2章 基于反射的UI测试第3章 基于Windows的UI测试第4章 测试套件设计模式第5章 请求-响应测试 第6章 基于脚本的Web UI测试第7章 底层的Web UI测试第8章 Web Service测试第9章 SQL存储过程测试 第10章 排列与组合第11章 ADO.NET测试第12章 XML测试

《软件测试自动化之道》读书笔记 之 SQL 存储过程测试

<软件测试自动化之道>读书笔记 之 SQL 存储过程测试 2014-09-28 待测程序测试程序   创建测试用例以及测试结果存储  执行T-SQL脚本  使用BCP工具导入测试用例数据  创建T-SQL 测试套件  当待测存储过程返回行集的时候,如何判断测试结果是否通过  当待测存储过程返回out参数时,如何判断测试结果是否通过  当待测存储过程没有返回值时,如何判断测试结果是否通过 许多基于Windows的系统都使用了SQL Server作为后台组件.待测程序经常通过存储过程来访问数据库.

《软件测试自动化之道》读书笔记 之 底层的Web UI 测试

<软件测试自动化之道>读书笔记 之 底层的Web UI 测试 2014-09-28 测试自动化程序的任务待测程序测试程序  启动IE并连接到这个实例  如何判断待测web程序完全加载到浏览器  操纵并检查IE Shell  操作待测Web页面上的HTML元素的值  验证Web页面上HTML元素  示例代码 测试自动化程序的任务 底层技术的核心是,通过直接调用mshtml.dll和shdocvw.dll库来访问并且操纵IE客户区域的HTML对象. 待测程序 新建一个网站“WebAUT”,删除原来

《软件测试自动化之道》读书笔记 之 基于Windows的UI测试

<软件测试自动化之道>读书笔记 之 基于Windows的UI测试 2014-09-25 测试自动化程序的任务待测程序测试程序  启动待测程序  获得待测程序主窗体的句柄  获得有名字控件的句柄  获得无名字控件的句柄  发送字符给控件  鼠标单击一个控件  处理消息对话框  处理菜单  检查应用程序状态  示例程序参考 本章主要讲述如何使用底层的Windows自动化技术通过用户界面来测试应用程序.这些技术涉及Win32 API的调用(比如FindWindow()函数)以及想待测程序发送Wind

《软件测试自动化之道》读书笔记 之 基于反射的UI测试

<软件测试自动化之道>读书笔记 之 基于反射的UI测试 2014-09-24 测试自动化程序的任务待测程序测试程序  启动待测程序  设置窗体的属性  获取窗体的属性  设置控件的属性  获取控件的属性  方法调用  待测程序代码 测试自动化程序的任务 返回 基于反射的ui测试自动化程序,要完成的6项任务: 通过某种方式从测试套件程序中运行待测程序(AUT: Applicaton Under Test),以便于两个程序之间进行通信 操纵应用程序的窗体,从而模拟用户对窗体所实施的moving和r

《赢在测试2-中国软件测试专家访谈录》读书笔记

<赢在测试2-中国软件测试专家访谈录>读书笔记 2015-04-30 测试人物经历与观点  1.董杰 百度测试架构师    董杰的职业发展经历    如何成长为一个优秀的测试工程师?    如何开展软件测试工作?  2.邰晓梅 独立测试咨询顾问    邰晓梅职业发展经历    测试与开发的关系    对测试认识的三个阶段  3.一些分析:对测试的一些想法 职业发展是一个探索和尝试的过程,职业发展的目标是动态的,也可能会变. 测试人物经历与观点 返回 1.董杰 百度测试架构师 董杰的职业发展经历

VC++编程之道读书笔记(2)

第三篇 技术细节 第七章:细说开发人员必知必会的39个开发细节 细节36:单例模式的应用 在开发程序时,往往需要在整个工程中只需要一个类的实例.而这个实例一旦被创建就不能被其他的实例再创建了,通常我们称这个实现过程为单例模式. 既然要保证类只有一个实例,那么就需要其他的类不能使用实例化该类.因此,需要将其构造方法设为私有的,即使用private关键字修饰.同时,类中提供一个静态方法,该方法的返回值是该类的一个实例.这样就只能使用该静态方法来获取类的实例了,从而保证了唯一性. 下面通过具体代码来实

VC++编程之道读书笔记

第二篇 缪误21:位图数据是按照红绿蓝顺序存储的 大家都知道位图的颜色是由红.绿.蓝三个分量构成的,但是位图颜色数据存储的方式则不是按照这个顺序存储的,而是按照蓝.绿.红的顺序存储的.并且对于真彩色位图来说,位图的颜色数据是倒序存储的,即位图的第一行数据位于位图数据的最底部. 第三篇 细节12 :内存中的数组 在C++中通过数组可以操作内存,创建数组时需要为数组分配内存空间,操作数组时就是对内存空间中的数组元素进行操作.数组创建后,数组引用和数组元素分别存储在栈内存和堆内存中,并通过数组引用与数

《微软的软件测试之道》读书笔记 之 结构测试技术

<微软的软件测试之道>读书笔记 之 结构测试技术 2014-07-18 我们需要结构测试吗? 微软的一项试验说明了结构测试的在代码覆盖中起到的效果: 超过3000名测试员参与了这项实验,每25人一组,实验结果在所有组中都是一致的.在这项研究中, 脚本化测试:根据样式书设计的脚本化测试在被测程序上达到了标称83%的代码覆盖率. 探索性测试:然后,实验参与者允许进行每人15分钟,累计5小时的探索性测试.令人惊讶的是,代码覆盖率平均只增加了3个百分点. 结构测试:但是,当实验参与者能够分析探测过的(