<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>口袋码头 house365 技术中心博客</title>
	<atom:link href="http://www.code365.org/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.code365.org</link>
	<description></description>
	<lastBuildDate>Tue, 15 May 2012 10:28:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>黑盒测试方法—等价类划分法</title>
		<link>http://www.code365.org/?p=3319</link>
		<comments>http://www.code365.org/?p=3319#comments</comments>
		<pubDate>Tue, 15 May 2012 10:26:58 +0000</pubDate>
		<dc:creator>chasedreem</dc:creator>
				<category><![CDATA[休闲时刻]]></category>
		<category><![CDATA[测试技术]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3319</guid>
		<description><![CDATA[1.概述 等价类划分方法是一种典型的、常用的黑盒测试方法，这种方法把全部输入数据合理划分为若干等价类，在每一个等价类中取一个数据作为测试的输入条件，就可以用少量有代表性的测试数据取得较好的测试效果，这种方法相比穷举法大大的提高了测试执行的效率。下面按照其分析步骤对该方法进行介绍。 2.等价类划分方法应用介绍 2.1划分等价类 首先把数目极多的输入情况划分成若干个等价类。所谓等价类是指某个输入域的集合。他的指导思想是如果用一个集合中的一个输入条件作为测试数据进行测试不能发现程序的错误，那么使用集合中的其他输入条件进行测试也不可能发现错误。 考虑等价类时，需要注意区别下面两种不同的情况： a) 有效等价类：指对于程序的规格说明来说是合理的，有意义的输入数据构成的集合。利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能。 b) 无效等价类：指对于程序的规格说明来说是不合理的，没有意义的输入数据构成的集合。   等价类的划分有一些原则： 原则1：如果输入条件规定了取值范围或值的格式，则可以确定一个有效等价类和两个无效等价类。例如：程序规格说明提到的输入条件包括“&#8230;&#8230;项数可以从1到999”，则可以去有效等价类为“1&#60;项数&#60;999”, 无效等价类为“项数&#60;1”及“项数&#62;999”。  原则2：输入条件规定了输入值的集合，或是规定了必须如何的条件，则可以确定一个有效等价类和一个无效等价类。例如，某程序规格说明中提到输入条件包括“&#8230;统计全国各省，市，自治区的人口”，则应该取“国内省，市，自治区”为有效等价类，非国内省，市，自治区为无效等价类。  原则3：如果我们确知，已经划分的等价类中各个元素在程序中的处理方式不同的，则应该将此等价类进一步划分。 等价类划分完成后，可以按照以下的形式将等价类列出： [1]    等价类划分表 输入条件 有效等价类 无效等价类 …… …… …… …… …… …… …… …… …… 2.2确定测试用例 根据列出的等价类表，按照以下步骤确定测试用例： （1）为每一个等价类规定一个唯一的编号； （2）设计一个测试用例，使其尽可能多的覆盖尚未覆盖的有效等价类。重复这一步，最后使得所有有效等价类均被测试用例所覆盖。 （3）设计一个新的测试用例，使其只覆盖一个无效等价类。重复这一步，最后使得所有无效等价类均被测试用例所覆盖。 注意：这里规定每次只覆盖一个无效等价类，这是因为，如果一个测试用例中 包含多个错误，则有可能在测试中发现其中的一个，另一个被忽视。 3.应用实例（三角形判断） 程序规格规定：“输入三个整数作为三边的边长构成三角形，当此三角形为一般三角形，等腰三角形和等边三角形时，分别计算&#8230;”，用等价类划分方法进行测试用例设计。 a)输入条件要求 1、整数； &#8230; <a href="http://www.code365.org/?p=3319">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>1.概述</p>
<p>等价类划分方法是一种典型的、常用的黑盒测试方法，这种方法把全部输入数据合理划分为若干等价类，在每一个等价类中取一个数据作为测试的输入条件，就可以用少量有代表性的测试数据取得较好的测试效果，这种方法相比穷举法大大的提高了测试执行的效率。下面按照其分析步骤对该方法进行介绍。<span id="more-3319"></span></p>
<p>2.等价类划分方法应用介绍</p>
<p>2.1划分等价类</p>
<p>首先把数目极多的输入情况划分成若干个等价类。所谓等价类是指某个输入域的集合。他的指导思想是如果用一个集合中的一个输入条件作为测试数据进行测试不能发现程序的错误，那么使用集合中的其他输入条件进行测试也不可能发现错误。</p>
<p>考虑等价类时，需要注意区别下面两种不同的情况：</p>
<p align="left">a) 有效等价类：指对于程序的规格说明来说是合理的，有意义的输入数据构成的集合。利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能。</p>
<p align="left">b) 无效等价类：指对于程序的规格说明来说是不合理的，没有意义的输入数据构成的集合。</p>
<p align="left">  等价类的划分有一些原则：</p>
<p align="left">原则1：如果输入条件规定了取值范围或值的格式，则可以确定一个有效等价类和两个无效等价类。例如：程序规格说明提到的输入条件包括“&#8230;&#8230;项数可以从1到999”，则可以去有效等价类为“1&lt;项数&lt;999”, 无效等价类为“项数&lt;1”及“项数&gt;999”。</p>
<p align="left"> 原则2：输入条件规定了输入值的集合，或是规定了必须如何的条件，则可以确定一个有效等价类和一个无效等价类。例如，某程序规格说明中提到输入条件包括“&#8230;统计全国各省，市，自治区的人口”，则应该取“国内省，市，自治区”为有效等价类，非国内省，市，自治区为无效等价类。</p>
<p align="left"> 原则3：如果我们确知，已经划分的等价类中各个元素在程序中的处理方式不同的，则应该将此等价类进一步划分。</p>
<p>等价类划分完成后，可以按照以下的形式将等价类列出：</p>
<p>[1]    等价类划分表</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="189">输入条件</td>
<td valign="top" width="189">有效等价类</td>
<td valign="top" width="189">无效等价类</td>
</tr>
<tr>
<td valign="top" width="189">……</td>
<td valign="top" width="189">……</td>
<td valign="top" width="189">……</td>
</tr>
<tr>
<td valign="top" width="189">……</td>
<td valign="top" width="189">……</td>
<td valign="top" width="189">……</td>
</tr>
<tr>
<td valign="top" width="189">……</td>
<td valign="top" width="189">……</td>
<td valign="top" width="189">……</td>
</tr>
</tbody>
</table>
<h4>2.2确定测试用例</h4>
<p>根据列出的等价类表，按照以下步骤确定测试用例：</p>
<p>（1）为每一个等价类规定一个唯一的编号；</p>
<p>（2）设计一个测试用例，使其尽可能多的覆盖尚未覆盖的有效等价类。重复这一步，最后使得所有有效等价类均被测试用例所覆盖。</p>
<p>（3）设计一个新的测试用例，使其只覆盖一个无效等价类。重复这一步，最后使得所有无效等价类均被测试用例所覆盖。</p>
<p>注意：这里规定每次只覆盖一个无效等价类，这是因为，如果一个测试用例中</p>
<p>包含多个错误，则有可能在测试中发现其中的一个，另一个被忽视。</p>
<p>3.应用实例（三角形判断）</p>
<p>程序规格规定：“输入三个整数作为三边的边长构成三角形，当此三角形为一般三角形，等腰三角形和等边三角形时，分别计算&#8230;”，用等价类划分方法进行测试用例设计。</p>
<h4>a)输入条件要求</h4>
<p>1、整数；</p>
<p>2、三个数；</p>
<p>3、非零数；</p>
<p>4、正数；</p>
<h4>b)输出条件要求</h4>
<p>1、两边之和大于第三边；</p>
<p>2、等腰；</p>
<p>3、等边；</p>
<p>列出等价类如下：</p>
<p>[1]    等价类划分表</p>
<table width="931" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="142"></td>
<td valign="top" width="142"></td>
<td valign="top" width="167">有效等价类</td>
<td valign="top" width="143">编号</td>
<td valign="top" width="167">无效等价类</td>
<td valign="top" width="171">编号</td>
</tr>
<tr>
<td rowspan="28" valign="top" width="142">输入条件</td>
<td rowspan="28" valign="top" width="142">输入三个整数</td>
<td rowspan="7" valign="top" width="167">整数</td>
<td rowspan="7" valign="top" width="143">1</td>
<td valign="top" width="167">一边为非整数－－a 为非整数</td>
<td valign="top" width="171">12</td>
</tr>
<tr>
<td valign="top" width="167">一边为非整数－－b 为非整数</td>
<td valign="top" width="171">13</td>
</tr>
<tr>
<td valign="top" width="167">一边为非整数－－c 为非整数</td>
<td valign="top" width="171">14</td>
</tr>
<tr>
<td valign="top" width="167">两边为非整数－－a,b 为非整数</td>
<td valign="top" width="171">15</td>
</tr>
<tr>
<td valign="top" width="167">两边为非整数－－b,c 为非整数</td>
<td valign="top" width="171">16</td>
</tr>
<tr>
<td valign="top" width="167">两边为非整数－－c,a 为非整数</td>
<td valign="top" width="171">17</td>
</tr>
<tr>
<td valign="top" width="167">三边为非整数－－a,b,c为非整数</td>
<td valign="top" width="171">18</td>
</tr>
<tr>
<td rowspan="7" valign="top" width="167">三个数</td>
<td rowspan="7" valign="top" width="143">2</td>
<td valign="top" width="167">只给一边－－输入a</td>
<td valign="top" width="171">19</td>
</tr>
<tr>
<td valign="top" width="167">只给一边－－输入b</td>
<td valign="top" width="171">20</td>
</tr>
<tr>
<td valign="top" width="167">只给一边－－输入c</td>
<td valign="top" width="171">21</td>
</tr>
<tr>
<td valign="top" width="167">只给两边－－输入a,b</td>
<td valign="top" width="171">22</td>
</tr>
<tr>
<td valign="top" width="167">只给两边－－输入b,c</td>
<td valign="top" width="171">23</td>
</tr>
<tr>
<td valign="top" width="167">只给两边－－输入c,a</td>
<td valign="top" width="171">24</td>
</tr>
<tr>
<td valign="top" width="167">给出三个以上</td>
<td valign="top" width="171">25</td>
</tr>
<tr>
<td rowspan="7" valign="top" width="167">非零数</td>
<td rowspan="7" valign="top" width="143">3</td>
<td valign="top" width="167">一边为零－－a 为0</td>
<td valign="top" width="171">26</td>
</tr>
<tr>
<td valign="top" width="167">一边为零－－b 为0</td>
<td valign="top" width="171">27</td>
</tr>
<tr>
<td valign="top" width="167">一边为零－－c 为0</td>
<td valign="top" width="171">28</td>
</tr>
<tr>
<td valign="top" width="167">两边为零－－a,b 为0</td>
<td valign="top" width="171">29</td>
</tr>
<tr>
<td valign="top" width="167">两边为零－－b,c 为0</td>
<td valign="top" width="171">30</td>
</tr>
<tr>
<td valign="top" width="167">两边为零－－c,a 为0</td>
<td valign="top" width="171">31</td>
</tr>
<tr>
<td valign="top" width="167">三边为零－－a,b,c为0</td>
<td valign="top" width="171">32</td>
</tr>
<tr>
<td rowspan="7" valign="top" width="167">正数</td>
<td rowspan="7" valign="top" width="143">4</td>
<td valign="top" width="167">一边&lt;0 －－a&lt;0</td>
<td valign="top" width="171">33</td>
</tr>
<tr>
<td valign="top" width="167">一边&lt;0 －－b&lt;0</td>
<td valign="top" width="171">34</td>
</tr>
<tr>
<td valign="top" width="167">一边&lt;0 －－c&lt;0</td>
<td valign="top" width="171">35</td>
</tr>
<tr>
<td valign="top" width="167">两边&lt;0 －－a&lt;0 &amp;&amp; b&lt;0</td>
<td valign="top" width="171">36</td>
</tr>
<tr>
<td valign="top" width="167">两边&lt;0 －－b&lt;0 &amp;&amp; c&lt;0</td>
<td valign="top" width="171">37</td>
</tr>
<tr>
<td valign="top" width="167">两边&lt;0 －－c&lt;0 &amp;&amp; a&lt;0</td>
<td valign="top" width="171">38</td>
</tr>
<tr>
<td valign="top" width="167">三边&lt;0－－a&lt;0 &amp;&amp; b&lt;0 &amp;&amp; c&lt;0</td>
<td valign="top" width="171">39</td>
</tr>
<tr>
<td rowspan="10" valign="top" width="142">输出条件</td>
<td rowspan="6" valign="top" width="142">构成三角形</td>
<td rowspan="2" valign="top" width="167">a+b&gt;c</td>
<td rowspan="2" valign="top" width="143">5</td>
<td valign="top" width="167">a+b&lt;c</td>
<td valign="top" width="171">40</td>
</tr>
<tr>
<td valign="top" width="167">a+b=c</td>
<td valign="top" width="171">41</td>
</tr>
<tr>
<td rowspan="2" valign="top" width="167">b+c&gt;a</td>
<td rowspan="2" valign="top" width="143">6</td>
<td valign="top" width="167">b+c&lt;a</td>
<td valign="top" width="171">42</td>
</tr>
<tr>
<td valign="top" width="167">b+c=a</td>
<td valign="top" width="171">43</td>
</tr>
<tr>
<td rowspan="2" valign="top" width="167">a+c&gt;b</td>
<td rowspan="2" valign="top" width="143">7</td>
<td valign="top" width="167">a+c&lt;b</td>
<td valign="top" width="171">44</td>
</tr>
<tr>
<td valign="top" width="167">a+c=b</td>
<td valign="top" width="171">45</td>
</tr>
<tr>
<td rowspan="3" valign="top" width="142">构成等腰三角形</td>
<td valign="top" width="167">a=b且两边之和大于第三边</td>
<td valign="top" width="143">8</td>
<td valign="top" width="167"></td>
<td valign="top" width="171"></td>
</tr>
<tr>
<td valign="top" width="167">b＝c且两边之和大于第三边</td>
<td valign="top" width="143">9</td>
<td valign="top" width="167"></td>
<td valign="top" width="171"></td>
</tr>
<tr>
<td valign="top" width="167">c=a且两边之和大于第三边</td>
<td valign="top" width="143">10</td>
<td valign="top" width="167"></td>
<td valign="top" width="171"></td>
</tr>
<tr>
<td valign="top" width="142">构成等边三角形</td>
<td valign="top" width="167">a=b=c</td>
<td valign="top" width="143">11</td>
<td valign="top" width="167"></td>
<td valign="top" width="171"></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>覆盖有效等价类：</p>
<p>[2]    覆盖有效等价类</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="284">输入a,b,c</td>
<td valign="top" width="284">覆盖等价类编号</td>
</tr>
<tr>
<td valign="top" width="284">3，4，5</td>
<td valign="top" width="284">1～7</td>
</tr>
<tr>
<td valign="top" width="284">4，4，5</td>
<td valign="top" width="284">1～7，8</td>
</tr>
<tr>
<td valign="top" width="284">4，5，5</td>
<td valign="top" width="284">1～7，9</td>
</tr>
<tr>
<td valign="top" width="284">5，4，5</td>
<td valign="top" width="284">1～7，10</td>
</tr>
<tr>
<td valign="top" width="284">4，4，4</td>
<td valign="top" width="284">1～7，11</td>
</tr>
</tbody>
</table>
<p>[3]    覆盖无效等价类</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="32">a</td>
<td valign="top" width="35">b</td>
<td valign="top" width="36">c</td>
<td valign="top" width="24">d</td>
<td valign="top" width="91">覆盖等价类编号</td>
<td valign="top" width="29">a</td>
<td valign="top" width="26">b</td>
<td valign="top" width="26">c</td>
<td valign="top" width="94">覆盖等价类编号</td>
<td valign="top" width="22">a</td>
<td valign="top" width="24">b</td>
<td valign="top" width="24">c</td>
<td valign="top" width="105">覆盖等价类编号</td>
</tr>
<tr>
<td valign="top" width="32">2.5</td>
<td valign="top" width="35">4</td>
<td valign="top" width="36">5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">12</td>
<td valign="top" width="29">0</td>
<td valign="top" width="26">4</td>
<td valign="top" width="26">5</td>
<td valign="top" width="94">26</td>
<td valign="top" width="22">3</td>
<td valign="top" width="24">1</td>
<td valign="top" width="24">5</td>
<td valign="top" width="105">40</td>
</tr>
<tr>
<td valign="top" width="32">3</td>
<td valign="top" width="35">4.5</td>
<td valign="top" width="36">5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">13</td>
<td valign="top" width="29">3</td>
<td valign="top" width="26">0</td>
<td valign="top" width="26">5</td>
<td valign="top" width="94">27</td>
<td valign="top" width="22">3</td>
<td valign="top" width="24">2</td>
<td valign="top" width="24">5</td>
<td valign="top" width="105">41</td>
</tr>
<tr>
<td valign="top" width="32">3</td>
<td valign="top" width="35">4</td>
<td valign="top" width="36">5.5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">14</td>
<td valign="top" width="29">3</td>
<td valign="top" width="26">4</td>
<td valign="top" width="26">0</td>
<td valign="top" width="94">28</td>
<td valign="top" width="22">3</td>
<td valign="top" width="24">1</td>
<td valign="top" width="24">1</td>
<td valign="top" width="105">42</td>
</tr>
<tr>
<td valign="top" width="32">3.5</td>
<td valign="top" width="35">4.5</td>
<td valign="top" width="36">5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">15</td>
<td valign="top" width="29">0</td>
<td valign="top" width="26">0</td>
<td valign="top" width="26">5</td>
<td valign="top" width="94">29</td>
<td valign="top" width="22">3</td>
<td valign="top" width="24">1</td>
<td valign="top" width="24">2</td>
<td valign="top" width="105">43</td>
</tr>
<tr>
<td valign="top" width="32">3</td>
<td valign="top" width="35">4.5</td>
<td valign="top" width="36">5.5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">16</td>
<td valign="top" width="29">3</td>
<td valign="top" width="26">0</td>
<td valign="top" width="26">0</td>
<td valign="top" width="94">30</td>
<td valign="top" width="22">1</td>
<td valign="top" width="24">4</td>
<td valign="top" width="24">2</td>
<td valign="top" width="105">44</td>
</tr>
<tr>
<td valign="top" width="32">3.5</td>
<td valign="top" width="35">4</td>
<td valign="top" width="36">5.5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">17</td>
<td valign="top" width="29">0</td>
<td valign="top" width="26">4</td>
<td valign="top" width="26">0</td>
<td valign="top" width="94">31</td>
<td valign="top" width="22">3</td>
<td valign="top" width="24">4</td>
<td valign="top" width="24">1</td>
<td valign="top" width="105">45</td>
</tr>
<tr>
<td valign="top" width="32">3.5</td>
<td valign="top" width="35">4.5</td>
<td valign="top" width="36">5.5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">18</td>
<td valign="top" width="29">0</td>
<td valign="top" width="26">0</td>
<td valign="top" width="26">0</td>
<td valign="top" width="94">32</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105">46</td>
</tr>
<tr>
<td valign="top" width="32">3</td>
<td valign="top" width="35"></td>
<td valign="top" width="36"></td>
<td valign="top" width="24"></td>
<td valign="top" width="91">19</td>
<td valign="top" width="29">-3</td>
<td valign="top" width="26">4</td>
<td valign="top" width="26">5</td>
<td valign="top" width="94">33</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105"></td>
</tr>
<tr>
<td valign="top" width="32"></td>
<td valign="top" width="35">4</td>
<td valign="top" width="36"></td>
<td valign="top" width="24"></td>
<td valign="top" width="91">20</td>
<td valign="top" width="29">3</td>
<td valign="top" width="26">-4</td>
<td valign="top" width="26">5</td>
<td valign="top" width="94">34</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105"></td>
</tr>
<tr>
<td valign="top" width="32"></td>
<td valign="top" width="35"></td>
<td valign="top" width="36">5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">21</td>
<td valign="top" width="29">3</td>
<td valign="top" width="26">4</td>
<td valign="top" width="26">-5</td>
<td valign="top" width="94">35</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105"></td>
</tr>
<tr>
<td valign="top" width="32">3</td>
<td valign="top" width="35">4</td>
<td valign="top" width="36"></td>
<td valign="top" width="24"></td>
<td valign="top" width="91">22</td>
<td valign="top" width="29">-3</td>
<td valign="top" width="26">4</td>
<td valign="top" width="26">5</td>
<td valign="top" width="94">36</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105"></td>
</tr>
<tr>
<td valign="top" width="32"></td>
<td valign="top" width="35">4</td>
<td valign="top" width="36">5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">23</td>
<td valign="top" width="29">3</td>
<td valign="top" width="26">-4</td>
<td valign="top" width="26">5</td>
<td valign="top" width="94">37</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105"></td>
</tr>
<tr>
<td valign="top" width="32">3</td>
<td valign="top" width="35"></td>
<td valign="top" width="36">5</td>
<td valign="top" width="24"></td>
<td valign="top" width="91">24</td>
<td valign="top" width="29">3</td>
<td valign="top" width="26">4</td>
<td valign="top" width="26">-5</td>
<td valign="top" width="94">38</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105"></td>
</tr>
<tr>
<td valign="top" width="32">3</td>
<td valign="top" width="35">4</td>
<td valign="top" width="36">5</td>
<td valign="top" width="24">6</td>
<td valign="top" width="91">25</td>
<td valign="top" width="29">-3</td>
<td valign="top" width="26">-4</td>
<td valign="top" width="26">-5</td>
<td valign="top" width="94">39</td>
<td valign="top" width="22"></td>
<td valign="top" width="24"></td>
<td valign="top" width="24"></td>
<td valign="top" width="105"></td>
</tr>
</tbody>
</table>
<p>注意：等价类划分方法设计测试用例的难点，是列出完整的输入输出条件。有些输入输出条件，是在软件规格中明确列出来了的，但是有的输入输出条件，例如例子中的3),4),5)则是需要在通过分析得到，这些隐含的软件规格，对于等价类划分的完备性是非常重要的。注意隐含的软件规格，对于我们来说是非常重要的，因为我们的很多规格都是包含在相应的信令协议，设备规范和业务规范。</p>
<p>4.等价类划分步骤</p>
<h4>1）划分等价类</h4>
<h4>2）边界值分析（可选步骤）</h4>
<h4>3）多个输入间关系分析（可选步骤）</h4>
<h4>4）生成测试用例</h4>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3319</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>软件测试对质量负主要责任？</title>
		<link>http://www.code365.org/?p=3312</link>
		<comments>http://www.code365.org/?p=3312#comments</comments>
		<pubDate>Wed, 09 May 2012 05:20:28 +0000</pubDate>
		<dc:creator>mmtme</dc:creator>
				<category><![CDATA[测试技术]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3312</guid>
		<description><![CDATA[你的公司，产品发布时，是否要求测试说出个“产品质量是XX的”论断，如果发到用户那里出了问题，就首先打测试的板子，老大都在问“测试为什么没有测试出来”，仿佛测试是最后一道关、是质量警察？测试应该对质量负主要的责任吗？ 我的观点：测试不对质量负主要责任，测试只起到质量辅助的作用；测试是一种服务，为其他角色提供服务，提供关于质量的信息。 为了说清这个观点，有必要先讨论一下：什么是质量、什么叫做对质量负责、对谁负责、谁定义的质量。 当然质量的定义有很多种，我比较赞赏Jerry Weinberg的定义”Quality is value to someone who matters“，测试最主要的目的就是要找到那些削弱产品价值（value）的点，将这些与产品质量相关的重要的信息提供给项目决策者，以便他们做出更 准确的决策。 正如Michael Bolton所言，”Consider quality not as something simple， objective， and abstract， but as something messy， subjective and very human.“ 质量不是什么简单的事务，而是一个关乎产品、人、系统之间的复杂关系。 为了提升质量或保证质量，需要有方方面面的考虑，是那些产品的管理者们真正有权利决定使用什么开发方法和流程、雇佣什么样的人员、采用什么样的质量目标、如何度量、花多大成本等等来确保产品的质量，而不是测试人员。 作为测试人员，不要努力去影响别人做什么、怎么做，而是要聚焦于提供实时的、准确的有关产品的信息（问题和风险），以有助于别人做出更恰当的提升质量的决策。 测试是一种服务，为项目其他角色提供服务。当然，每一个角色都是为其他角色提供服务的。开发人员为测试人员提供”软件可测试“的服务，使得软件更容易测试；测试人员帮助开发人员测试他们的代码，使用专业的测试技能和测试思维。 测试人员、包括QA，都不应该将某种方法强加于开发人员，那是质量警察干的事。一是因为测试人员和QA都没有优势告诉开发如何开发质量更好的产品；二是因为当你强加某种东西给别人的时候，你获得的往往是假的数据。 其实，“负责”是个很重的词。对质量负主要责任的人，得有一定的权力做各种质量有关的决定。测试是否有权力或能力做这些决定呢？ 质量本身是一系列活动的结果，当然最重要的是设计和编码，如果设计和编码都完全符合需求和用户期望，那也就不需要测试了。然而，我们的认知和智力都是有限的，不可能那么完美，而且有时候用户都不知道自己的需求，还需要我们去引导（乔布斯理论），所以还是需要一个中立的或者第三方的组织来判断产品的实 现是否符合用户和我们最初的需求和期望，这就需要测试来给相关的利益关系者提供客观、准确的质量信息和评估了。 测试活动本身不能带来产品质量的变化。测试就是一个信息提供方，精确反映出产品需求的实现和在哪种情况可能给客户带来的风险就是测试的职责，当做一个质量播报员，就像最近的牛奶风波一样，我们只要把牛奶中成分的真实情况反映出来，剩下的就由用户或制造者来做决定吧。 质量是设计出来的，但设计者是人，也有考虑不足的，需要通过测试发现，发现后设计者进行改进，测试的职责是发现问题。设计和实现是有差距的，没有缺 &#8230; <a href="http://www.code365.org/?p=3312">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>你的公司，产品发布时，是否要求<a href="http://www.51testing.com/html/26/n-812426.html" target="_self"><span style="text-decoration: underline"><strong>测试</strong></span></a>说出个“产品质量是XX的”论断，如果发到用户那里出了问题，就首先打测试的板子，老大都在问“测试为什么没有测试出来”，仿佛测试是最后一道关、是质量警察？测试应该对质量负主要的责任吗？</p>
<p>我的观点：测试不对质量负主要责任，测试只起到质量辅助的作用；测试是一种服务，为其他角色提供服务，提供关于质量的信息。</p>
<p>为了说清这个观点，有必要先讨论一下：什么是质量、什么叫做对质量负责、对谁负责、谁定义的质量。</p>
<p>当然质量的定义有很多种，我比较赞赏Jerry Weinberg的定义”Quality is value to someone who matters“，测试最主要的目的就是要找到那些削弱产品价值（value）的点，将这些与产品质量相关的重要的信息提供给项目决策者，以便他们做出更 准确的决策。</p>
<p>正如Michael Bolton所言，”Consider quality not as something simple， objective， and abstract， but as something messy， subjective and very human.“ 质量不是什么简单的事务，而是一个关乎产品、人、系统之间的复杂关系。</p>
<p>为了提升质量或保证质量，需要有方方面面的考虑，是那些产品的管理者们真正有权利决定使用什么开发方法和流程、雇佣什么样的人员、采用什么样的质量目标、如何度量、花多大成本等等来确保产品的质量，而不是测试人员。</p>
<p>作为测试人员，不要努力去影响别人做什么、怎么做，而是要聚焦于提供实时的、准确的有关产品的信息（问题和风险），以有助于别人做出更恰当的提升质量的决策。</p>
<p>测试是一种服务，为项目其他角色提供服务。当然，每一个角色都是为其他角色提供服务的。开发人员为测试人员提供”软件可测试“的服务，使得软件更容易测试；测试人员帮助开发人员测试他们的代码，使用专业的测试技能和测试思维。</p>
<p>测试人员、包括QA，都不应该将某种方法强加于开发人员，那是质量警察干的事。一是因为测试人员和QA都没有优势告诉开发如何开发质量更好的产品；二是因为当你强加某种东西给别人的时候，你获得的往往是假的数据。</p>
<p>其实，“负责”是个很重的词。对质量负主要责任的人，得有一定的权力做各种质量有关的决定。测试是否有权力或能力做这些决定呢？</p>
<p>质量本身是一系列活动的结果，当然最重要的是设计和编码，如果设计和编码都完全符合需求和用户期望，那也就不需要测试了。然而，我们的认知和智力都是有限的，不可能那么完美，而且有时候用户都不知道自己的需求，还需要我们去引导（乔布斯理论），所以还是需要一个中立的或者第三方的组织来判断产品的实 现是否符合用户和我们最初的需求和期望，这就需要测试来给相关的利益关系者提供客观、准确的质量信息和评估了。</p>
<p>测试活动本身不能带来产品质量的变化。测试就是一个信息提供方，精确反映出产品需求的实现和在哪种情况可能给客户带来的风险就是测试的职责，当做一个质量播报员，就像最近的牛奶风波一样，我们只要把牛奶中成分的真实情况反映出来，剩下的就由用户或制造者来做决定吧。</p>
<p>质量是设计出来的，但设计者是人，也有考虑不足的，需要通过测试发现，发现后设计者进行改进，测试的职责是发现问题。设计和实现是有差距的，没有缺 陷的设计只是一个终极目标，只是一种理想，因此测试必须进行一种权衡，判断哪些缺陷是必须改进的，哪些是现在可以忽略的，这种决定不是仅由测试说了算的。我不知道哪个团队的测试人员可以做这个决策？除非你比开发人员还懂业务、你比项目经理还了解风险、你比客户还了解需求？</p>
<p>产品“零缺陷”只能是一个理想，即使排除时间和投入成本也是不可能达到的。但我们要把产品可能存在的潜在风险和失效条件找出来，发布与否这样的决定就不是测试说了算了，要看客户能否容忍这样的风险和失效，由决策者做成最终决定。</p>
<p>当然，测试这把尺子，只能提供有关产品质量的“相对”的信息，不是“绝对”的信息。实际上，“XX产品的质量就是什么样子的“这个论断没有人能给得出。如果你能准确无误地说出”XX产品的质量现在就是这样“， 很快就会发现一个反例的出现将打破你原来对它的认识–当然，你根本无法准确无误地说出质量的样子，那是一个无穷的集合，就像测试是一个永远测不完的活一 样。因此，测试提供的信息只是相对准确的，不是绝对准确的，这个局限性也正是测试所面临的挑战。</p>
<p>不过，测试努力做到的是，用我们的专业技能和测试思维，尽可能<a href="http://www.51testing.com/html/26/n-812426.html" target="_self"><span style="text-decoration: underline"><strong>学习</strong></span></a>了解真实的产品、发现别的角色意想不到的问题和风险，并报告给他们：”在XXX的 背景/上下文/场景下，XXX产品在XXX质量属性方面表现正常；在当前进行了XXX的测试后，目前XXX产品存在XXX的问题，如果XXX使用该产品， 会存在XXX的风险。“</p>
<p>说“测试对质量负主要责任”这样的说法是错误的，不是代表测试就和质量没有关系，实际上测试非常关心质量，并且测试的<a href="http://www.51testing.com/html/26/n-812426.html" target="_self"><span style="text-decoration: underline"><strong>工作</strong></span></a>对质量有很大的影响。但同时我们认为其他角色关心质量的程度一点也不 比我们小，或者不应该比我们小，大家共同对质量负责。但是像<a href="http://www.51testing.com/html/26/n-812426.html" target="_self"><span style="text-decoration: underline"><strong>敏捷</strong></span></a>里的“完整团队”的说法，每个人都对质量负责、大家是个自组织团队的做法在现实中还是遇到 很多问题的，还是得有人做决策，做那些为了提升质量而采取什么动作的决策，这个决策者，首先得有权利做决策，才能控制了项 目，才能控制了质量，才能对质量负责。</p>
<p>也许在很多公司，是<a href="http://www.51testing.com/html/26/n-812426.html" target="_self"><span style="text-decoration: underline"><strong>项目管理</strong></span></a>者有这样的权力吧。测试像一把尺子衡量产品质量后会给出测试知道的有关质量的信息，同时我们也很清楚，管理者那里还有很多测试不知道的、同样也很重要的、有关质量的信息，管理者会基于所有信息作出最终的质量决策，可能是发布产品、可能是更改流程、可能是更改需求、可能是引入工具&#8230;&#8230;管理者有做这些决策的权利和能力，他们会想办法让所有角色关心质量，所以，不是测试对质量负主要责任，而是决策者要对他做的决定负责。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3312</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>软件测试是要技术还是要业务</title>
		<link>http://www.code365.org/?p=3290</link>
		<comments>http://www.code365.org/?p=3290#comments</comments>
		<pubDate>Wed, 02 May 2012 02:39:44 +0000</pubDate>
		<dc:creator>mmtme</dc:creator>
				<category><![CDATA[测试技术]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3290</guid>
		<description><![CDATA[测试是个很特殊的职业，随着工作年龄的增长，相信很多人都体会到业务和经验积累的重要性，但是随着也会产生一个让人苦恼的问题，相信这问题也困扰过很多充满激情的测试工程师们：我要专注于技术还是业务呢？有时候我觉得选择在很多情况下是一个很多余的事情，重要的不是选择，而是心境。 不妨看一下测试工作者面临的或者可能面临的主要问题： 1）技术感不强 2）工作压力大 3）成就感不高 解释下罗列的几个问题： 1）技术感不强 　　经常从事业务和流程测试的工程师们可能会有这个感觉，如果日常的工作中业务理解要求很高，技术就算不懂也可以，照样可以把工作做的很好。而有一身自动化和性能测试技术的工程师如果刚入行并不了解实际业务，可能在工作开展中并不是那么顺利而这种不利会极大的损害工程师引以为傲的自信。上述的状况会造成两种倾向：对技术追求强烈的人可能会因为没有比较好的钻研目标而满怀失望，对自身要求不高的人会只关注于经验业务的积累却对技术研究和效率视而不见，殊不知无论是丢了业务还是丢了技术，对企业和个人都是重大的损失。 2）测试压力大 　　铺天盖地的需求，紧锣密鼓的发版，突发而现的问题……，测试压力不是一般的大，这个现象是不用怀疑的，少壮不努力，长大做IT的顺口溜应势而生，而今的IT再也不是一二十年前的IT了，当年别说测试了，搞IT的人都很少，经过多年的迅猛发展，IT的技术和产品业务复杂程度已经从波澜不惊发展现在的让人眼花缭乱的程度，在这种乱战的局面中，也很容易给人造成一种感觉：压力无处不在。 3）成就感不高 　　这里的成就感主要指是来自于工作结果的成就感。如果一个复杂的工作经历过艰难险阻终于最终完成了，这种成就感是一种从苦难中解脱的感觉，是很辛苦的成就感；如果一个复杂的工作在四两拨千斤之后最终完成的很漂亮，这种成就感是一种胜利的感觉。我们的测试人员多数很需要这种胜利的感觉。可能很多人都会说：让我远离第一个辛苦的成就感远一点吧，也有人会说：我连这种感觉都没有了，已经麻木了！ 关于成就感，和测试人员自身的自我认识和感知是密切相关的。是否认识到测试这个职业的价值，是否认识到测试的定位，是否认识到自己把工作做到了极致等等都会影响到成就感的获取。历史和现实都告诉我们：成就感是工作和生活得到快乐的基本要素之一。年轻的时候多一点辛苦成就感是很有必要的，是快速成长的必经之路，但是不能把这种成就感当作一种常态，很容易陷入空有激情却没有办法突围的状况，要把胜利和效率当作自己成就感的长期目标。这里重点推荐的是做事要有思路。一个想要成就感的人，最起码应该想办法把事情做好特别是简单的事情，也要注意总结完善自己的体系使自己做事情更有思路或依据，如工作方法、知识体系和规律等。就测试工作而言确实很多时候都是些看起来平常琐碎的工作，真的想做到尽善尽美并不是容易的事情，但是相信如果能做到凡事都有想法和思路而不是疲于应付，距离真正的豁然开朗就不远了。 如果你是个喜欢偷懒的人，也不想长期经历那种痛苦中解脱的成就感，或许你是正发愁自己带的兵受不了压力而跑路，不妨顺便思考一下这个问题：铁打的算盘流水的兵，是兵的错还是算盘的错？和第一部分提出的三个问题有没有直接关系？这问题不难，多数都是兵没有在算盘上找到自己的位置或者算盘并没有认识到兵的价值。而现实中一般纠结于技术和业务的方向问题的工程师往往考虑最多的是：我要在什么样的算盘上专注？换工作换环境能不能解决我的问题？如果你不能很好的解决文中三个主要问题的思考，这些纠结的疑问在很多场景下将会一直无法得到很好的解决。大家应该能体会的出来，这些问题的本质都是一样的，就个人的因素而言关键还是心境，积极的人解放生活，消极的人抹杀人生，天下之事莫不如此。 落霞与孤鹜齐飞，秋水共长天一色，王勃在写下这千古名句的时候，正值青春年少意气风发的时候，所有的一切在他眼睛里都是那么充满生机和活力，而今的我们也许并没有古人那份洒脱，但是并不妨碍我们在忙里偷闲之余感受一下内心思考的力量。如果你是属于那种还在纠结的不知道如何选择的人，不妨静下心来，感受一下当年的才子是怎么想的，自己的心不会骗人。我也想告诉正在纠结和彷徨的测试工程师们：如果你想成为举重轻重的力量，请好好重视本文的问题并找到正确的答案，相信这个答案也是毫无疑问的。人生在世，寻找真正的自我是一个非常艰难的道路，但是并非没有机会，保持内心心境的平和，做到认真而不放弃目标，人生会无比充实。]]></description>
			<content:encoded><![CDATA[<p>测试是个很特殊的职业，随着工作年龄的增长，相信很多人都体会到业务和经验积累的重要性，但是随着也会产生一个让人苦恼的问题，相信这问题也困扰过很多充满激情的测试工程师们：我要专注于技术还是业务呢？有时候我觉得选择在很多情况下是一个很多余的事情，重要的不是选择，而是心境。</p>
<p>不妨看一下测试工作者面临的或者可能面临的主要问题：</p>
<p>1）技术感不强</p>
<p>2）工作压力大</p>
<p>3）成就感不高</p>
<p>解释下罗列的几个问题：</p>
<p>1）技术感不强 　　经常从事业务和流程测试的工程师们可能会有这个感觉，如果日常的工作中业务理解要求很高，技术就算不懂也可以，照样可以把工作做的很好。而有一身自动化和性能测试技术的工程师如果刚入行并不了解实际业务，可能在工作开展中并不是那么顺利而这种不利会极大的损害工程师引以为傲的自信。上述的状况会造成两种倾向：对技术追求强烈的人可能会因为没有比较好的钻研目标而满怀失望，对自身要求不高的人会只关注于经验业务的积累却对技术研究和效率视而不见，殊不知无论是丢了业务还是丢了技术，对企业和个人都是重大的损失。</p>
<p>2）测试压力大 　　铺天盖地的需求，紧锣密鼓的发版，突发而现的问题……，测试压力不是一般的大，这个现象是不用怀疑的，少壮不努力，长大做IT的顺口溜应势而生，而今的IT再也不是一二十年前的IT了，当年别说测试了，搞IT的人都很少，经过多年的迅猛发展，IT的技术和产品业务复杂程度已经从波澜不惊发展现在的让人眼花缭乱的程度，在这种乱战的局面中，也很容易给人造成一种感觉：压力无处不在。</p>
<p>3）成就感不高 　　这里的成就感主要指是来自于工作结果的成就感。如果一个复杂的工作经历过艰难险阻终于最终完成了，这种成就感是一种从苦难中解脱的感觉，是很辛苦的成就感；如果一个复杂的工作在四两拨千斤之后最终完成的很漂亮，这种成就感是一种胜利的感觉。我们的测试人员多数很需要这种胜利的感觉。可能很多人都会说：让我远离第一个辛苦的成就感远一点吧，也有人会说：我连这种感觉都没有了，已经麻木了！</p>
<p>关于成就感，和测试人员自身的自我认识和感知是密切相关的。是否认识到测试这个职业的价值，是否认识到测试的定位，是否认识到自己把工作做到了极致等等都会影响到成就感的获取。历史和现实都告诉我们：成就感是工作和生活得到快乐的基本要素之一。年轻的时候多一点辛苦成就感是很有必要的，是快速成长的必经之路，但是不能把这种成就感当作一种常态，很容易陷入空有激情却没有办法突围的状况，要把胜利和效率当作自己成就感的长期目标。这里重点推荐的是做事要有思路。一个想要成就感的人，最起码应该想办法把事情做好特别是简单的事情，也要注意总结完善自己的体系使自己做事情更有思路或依据，如工作方法、知识体系和规律等。就测试工作而言确实很多时候都是些看起来平常琐碎的工作，真的想做到尽善尽美并不是容易的事情，但是相信如果能做到凡事都有想法和思路而不是疲于应付，距离真正的豁然开朗就不远了。</p>
<p>如果你是个喜欢偷懒的人，也不想长期经历那种痛苦中解脱的成就感，或许你是正发愁自己带的兵受不了压力而跑路，不妨顺便思考一下这个问题：铁打的算盘流水的兵，是兵的错还是算盘的错？和第一部分提出的三个问题有没有直接关系？这问题不难，多数都是兵没有在算盘上找到自己的位置或者算盘并没有认识到兵的价值。而现实中一般纠结于技术和业务的方向问题的工程师往往考虑最多的是：我要在什么样的算盘上专注？换工作换环境能不能解决我的问题？如果你不能很好的解决文中三个主要问题的思考，这些纠结的疑问在很多场景下将会一直无法得到很好的解决。大家应该能体会的出来，这些问题的本质都是一样的，就个人的因素而言关键还是心境，积极的人解放生活，消极的人抹杀人生，天下之事莫不如此。</p>
<p>落霞与孤鹜齐飞，秋水共长天一色，王勃在写下这千古名句的时候，正值青春年少意气风发的时候，所有的一切在他眼睛里都是那么充满生机和活力，而今的我们也许并没有古人那份洒脱，但是并不妨碍我们在忙里偷闲之余感受一下内心思考的力量。如果你是属于那种还在纠结的不知道如何选择的人，不妨静下心来，感受一下当年的才子是怎么想的，自己的心不会骗人。我也想告诉正在纠结和彷徨的测试工程师们：如果你想成为举重轻重的力量，请好好重视本文的问题并找到正确的答案，相信这个答案也是毫无疑问的。人生在世，寻找真正的自我是一个非常艰难的道路，但是并非没有机会，保持内心心境的平和，做到认真而不放弃目标，人生会无比充实。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3290</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于测试用例</title>
		<link>http://www.code365.org/?p=3286</link>
		<comments>http://www.code365.org/?p=3286#comments</comments>
		<pubDate>Wed, 02 May 2012 02:33:28 +0000</pubDate>
		<dc:creator>测试小张</dc:creator>
				<category><![CDATA[学习笔记]]></category>
		<category><![CDATA[测试技术]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3286</guid>
		<description><![CDATA[测试用例的定义：通过用例（Use  Cases）或业务场景来设计测试，用例描述了参与者（包括用户与系统）之间的相互作用，并从这些交互产生一个从用户的角度所期望和能观察到的结果；每个用例都有测试前置条件，这是用例成功执行的必要条件。每个用例结束后都存在后置条件，这是在用例执行完成后能观察到的结果和系统的结束状态； &#160; 用例测试技术的价值 基于用例的测试技术适合于测试典型的用户系统交互。因此，将这种技术应用在验收测试和系统测试中是最好的； 另外，测试规格说明工具可以用于支持用例测试技术。其他测试技术（如边界值分析）可以在这方面做些辅助； &#160; 测试用例必要信息 开始情况和前置条件； 其他可能的条件； 期望结果； 后置条件]]></description>
			<content:encoded><![CDATA[<p>测试用例的定义：通过用例（Use  Cases）或业务场景来设计测试，用例描述了参与者（包括用户与系统）之间的相互作用，并从这些交互产生一个从用户的角度所期望和能观察到的结果；每个用例都有测试前置条件，这是用例成功执行的必要条件。每个用例结束后都存在后置条件，这是在用例执行完成后能观察到的结果和系统的结束状态；<span id="more-3286"></span></p>
<p>&nbsp;</p>
<p>用例测试技术的价值</p>
<p>基于用例的测试技术适合于测试典型的用户系统交互。因此，将这种技术应用在验收测试和系统测试中是最好的；</p>
<p>另外，测试规格说明工具可以用于支持用例测试技术。其他测试技术（如边界值分析）可以在这方面做些辅助；</p>
<p>&nbsp;</p>
<p>测试用例必要信息</p>
<p>开始情况和前置条件；</p>
<p>其他可能的条件；</p>
<p>期望结果；</p>
<p>后置条件</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3286</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>测试不是和开发对立关系</title>
		<link>http://www.code365.org/?p=3249</link>
		<comments>http://www.code365.org/?p=3249#comments</comments>
		<pubDate>Wed, 02 May 2012 02:03:58 +0000</pubDate>
		<dc:creator>测试小张</dc:creator>
				<category><![CDATA[学习笔记]]></category>
		<category><![CDATA[测试技术]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3249</guid>
		<description><![CDATA[首先在说明两者不是对立关系前，要给我们测试申冤，反驳一下很多人包括开发人员也好普通人也好对测试存在的误区: 第一：测试活动是整个开发生命周期中的一个阶段，测试活动在开发活动之后； 事实是，在开发开始时，测试也开始按照PRD了解需求，编写测试方案，大型的项目如租售宝还有用例需要写，常常有人问我你在测试吗？我回答一旦是不在，对方立马接收一个错误讯息“哦，那就是没事干了”。身为一个测试人员，我们的工作不是仅仅是测试啊！我们不是天天工作时间都在测试工作单的，测试是需要测试设计的。一个工作单那么多测试点，如果我们没有测试之前做了准备，天马行空的进行测试那么经我们测试过的需求恐怕还会有很多缺陷的。 第二：软件质量是由测试人员决定的， 假如客户发现缺陷，那是测试人员的责任； 事实上，刚开始测试时我也存在这个误区，我还记得是测试茶坊的小游戏，开始时我胆战心惊，我想啊，这个出现很多Bug就是我的责任啊，质量不行就是我的不对啊！实际上后来我认识到一个软件的质量不是我们决定的，其实很大程度上一个熟练且有经验的开发人员开发出的产品质量会好于一个刚开始做开发工作的新人。我们测试的工作是发现存在的bug，是和开发互相合作，假如客户发现缺陷，不能全然是我们测试的责任，开发也负有一定的责任的。 第三：测试人员不需要具备很高的技能， 能力不佳的人才去做测试人员； 如果做过测试的人就会知道测试没想象中那么简单，恰如租售宝就写了300多条测试用例。在测试时，一个关键字搜索按照不同的PRD最少也能写个十几二十条的测试点。作为一个初级或者说入门级的测试，我觉得我要学习的地方很多很多。所以说，测试人员不是人们想象中那样简简单单的找错误，像玩找不同游戏那样的，是需要具备一定的技能的。 第四：测试工作是测试人员的事情，和开发人员无关； 测试在工作中需要开发的帮助，就说最简单的，在后台增加一个功能，测试不参与开发并不知道具体在哪，开发需要告知。而测试人员发现bug告知开发人员，开发人员进行修改，提高软件质量。另一方面，开发的过程中也有测试一个环节，开发也要做一个自测的工作，所以测试工作和开发息息相关，开发人员的工作不是完成了开发之后就和测试撇清了。 第五：测试工作的多少，或者工作量 ，是由项目的进度来决定的，时间多就多做一点 ，少就少做一点； 第六：软件测试工作是没有前途的； 第七：自动化测试将会取代手动测试； &#8230;&#8230; 这些都是对于我们测试的误解，而不是事实！ 要承认的是，测试人员(tester)和开发人员(developer)思维方式的确存在很大的的差异:开发是建设性的活动,而测试是可以看成破坏性的，但是测试不是搞破坏的，测试工作对于软件产品风险管理却是建设性的！ 开发也会自测自己做出的东西，可是很显然，一个人同时要有建设性思维和破坏性思维是不太可能的。因此，提高测试的效率和质量，需要将开发人员和测试人员分开。 开发和测试是合作而不是争斗的方式开始项目，虽然测试提交的bug会影响开发的绩效，但是提醒项目的每位成员：测试人员(tester)和开发人员(developer)共同目标是追求高质量的产品，所以请理解测试人员的工作，测试人员也是为了追求高质量的产品。 对产品中发现的问题以中性的和以事实为依据的方式来沟通，而不要指责引入这个问题的小组成员或个人。比如，客观而实际地编写缺陷报告和评审发现的问题； 总而言之，测试和开发不是对立关系，是相辅相成的合作关系，只有建立了良好的合作关系，相互理解，相互帮助，才能合力最终完成一个高质量的产品。]]></description>
			<content:encoded><![CDATA[<p><strong>首先在说明两者不是对立关系前，要给我们测试申冤，反驳一下很多人包括开发人员也好普通人也好对测试存在的误区:<span id="more-3249"></span></strong></p>
<p><strong>第一：测试活动是整个开发生命周期中的一个阶段，测试活动在开发活动之后；</strong></p>
<p>事实是，在开发开始时，测试也开始按照PRD了解需求，编写测试方案，大型的项目如租售宝还有用例需要写，常常有人问我你在测试吗？我回答一旦是不在，对方立马接收一个错误讯息“哦，那就是没事干了”。身为一个测试人员，我们的工作不是仅仅是测试啊！我们不是天天工作时间都在测试工作单的，测试是需要测试设计的。一个工作单那么多测试点，如果我们没有测试之前做了准备，天马行空的进行测试那么经我们测试过的需求恐怕还会有很多缺陷的。</p>
<p><strong>第二：软件质量是由测试人员决定的， 假如客户发现缺陷，那是测试人员的责任；</strong></p>
<p>事实上，刚开始测试时我也存在这个误区，我还记得是测试茶坊的小游戏，开始时我胆战心惊，我想啊，这个出现很多Bug就是我的责任啊，质量不行就是我的不对啊！实际上后来我认识到一个软件的质量不是我们决定的，其实很大程度上一个熟练且有经验的开发人员开发出的产品质量会好于一个刚开始做开发工作的新人。我们测试的工作是发现存在的bug，是和开发互相合作，假如客户发现缺陷，不能全然是我们测试的责任，开发也负有一定的责任的。</p>
<p><strong>第三：测试人员不需要具备很高的技能， 能力不佳的人才去做测试人员；</strong></p>
<p>如果做过测试的人就会知道测试没想象中那么简单，恰如租售宝就写了300多条测试用例。在测试时，一个关键字搜索按照不同的PRD最少也能写个十几二十条的测试点。作为一个初级或者说入门级的测试，我觉得我要学习的地方很多很多。所以说，测试人员不是人们想象中那样简简单单的找错误，像玩找不同游戏那样的，是需要具备一定的技能的。</p>
<p><strong>第四：测试工作是测试人员的事情，和开发人员无关；</strong></p>
<p>测试在工作中需要开发的帮助，就说最简单的，在后台增加一个功能，测试不参与开发并不知道具体在哪，开发需要告知。而测试人员发现bug告知开发人员，开发人员进行修改，提高软件质量。另一方面，开发的过程中也有测试一个环节，开发也要做一个自测的工作，所以测试工作和开发息息相关，开发人员的工作不是完成了开发之后就和测试撇清了。</p>
<p><strong>第五：测试工作的多少，或者工作量 ，是由项目的进度来决定的，时间多就多做一点 ，少就少做一点；</strong></p>
<p><strong>第六：软件测试工作是没有前途的；</strong></p>
<p><strong>第七：自动化测试将会取代手动测试；</strong></p>
<p><strong>&#8230;&#8230;</strong></p>
<p><strong>这些都是对于我们测试的误解，而不是事实！</strong></p>
<p><strong>要承认的是，测试人员(tester)和开发人员(developer)思维方式的确存在很大的的差异:开发是建设性的活动,而测试是可以看成破坏性的，但是测试不是搞破坏的，测试工作对于软件产品风险管理却是建设性的！</strong></p>
<p>开发也会自测自己做出的东西，可是很显然，一个人同时要有建设性思维和破坏性思维是不太可能的。因此，提高测试的效率和质量，需要将开发人员和测试人员分开。</p>
<p>开发和测试是合作而不是争斗的方式开始项目，虽然测试提交的bug会影响开发的绩效，但是提醒项目的每位成员：测试人员(tester)和开发人员(developer)共同目标是追求高质量的产品，所以请理解测试人员的工作，测试人员也是为了追求高质量的产品。</p>
<p>对产品中发现的问题以中性的和以事实为依据的方式来沟通，而不要指责引入这个问题的小组成员或个人。比如，客观而实际地编写缺陷报告和评审发现的问题；</p>
<p>总而言之，测试和开发不是对立关系，是相辅相成的合作关系，只有建立了良好的合作关系，相互理解，相互帮助，才能合力最终完成一个高质量的产品。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3249</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>转：LoadRunner协议选择方法</title>
		<link>http://www.code365.org/?p=3280</link>
		<comments>http://www.code365.org/?p=3280#comments</comments>
		<pubDate>Tue, 01 May 2012 03:31:58 +0000</pubDate>
		<dc:creator>冰冰</dc:creator>
				<category><![CDATA[休闲时刻]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3280</guid>
		<description><![CDATA[任何高级协议的底层都是用Winsocket通信 不管你系统中有多少个服务器，lr录制的始终是客户端与第一个服务器之间的通信内容, 客户端用IE访问的一般都选http协议（对于常见的，b/s系统，选择Web(Http/Html)） LR是怎么样工作的：LR捕捉API(应用程序接口)请求然后再把它们回放，既然大部分网络协议都是架构在winsocket协议之上的，那对于lr不支持的协议，我们都可以在winsocket层上录制脚本。所以当找不到合适协议的时候，可以选择winsocket来录制。 LR选择协议只考虑与直接加压的机器间通信所采用的协议，就是客户端 协议选择请确认系统，还有后台是什么数据库，再选择正确的协议 “双协议 Web/WinSock”的引擎使用一种不同的机制，因此应视为单协议并且不能与其他多协议类型结合使用。 HTTP或Winsocket做为唯一协议脚本时选项不可用。 8．C/S系统：根据C/S结构所用到的后台数据库来选择不同的协议,如果后台数据库是sybase，则采用sybaseCTlib协议，如果是sql server,则使用MS sql server的协议，至于oracle 数据库系统，当然就使用oracle 2-tier协议。 9．没有数据库的c/s（ftp,smtp）这些可以选择windwos wockets协议。 10. 应用程序部署解决方案：适用于 Citrix 协议。 11. 客户端 L服务器：适用于 MS SQL、 ODBC、 Oracle （两层）、 DB2 CLI、 .Sybase Ctlib、 Sybase Dblib、 Windows Sockets 和 DNS 协议。 &#8230; <a href="http://www.code365.org/?p=3280">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<ol>
<li>任何高级协议的底层都是用Winsocket通信</li>
<li>不管你系统中有多少个服务器，lr录制的始终是客户端与第一个服务器之间的通信内容, 客户端用IE访问的一般都选http协议（对于常见的，b/s系统，选择Web(Http/Html)）</li>
<li>LR是怎么样工作的：LR捕捉API(应用程序接口)请求然后再把它们回放，既然大部分网络协议都是架构在winsocket协议之上的，那对于lr不支持的协议，我们都可以在winsocket层上录制脚本。所以当找不到合适协议的时候，可以选择winsocket来录制。</li>
<li>LR选择协议只考虑与直接加压的机器间通信所采用的协议，就是客户端</li>
<li>协议选择请确认系统，还有后台是什么数据库，再选择正确的协议</li>
<li>“双协议 Web/WinSock”的引擎使用一种不同的机制，因此应视为单协议并且不能与其他多协议类型结合使用。</li>
<li>HTTP或Winsocket做为唯一协议脚本时选项不可用。</li>
</ol>
<p>8．C/S系统：根据C/S结构所用到的后台数据库来选择不同的协议,如果后台数据库是sybase，则采用sybaseCTlib协议，如果是sql server,则使用MS sql server的协议，至于oracle 数据库系统，当然就使用oracle 2-tier协议。</p>
<p>9．没有数据库的c/s（ftp,smtp）这些可以选择windwos wockets协议。</p>
<p>10. 应用程序部署解决方案：适用于 Citrix 协议。</p>
<p>11. 客户端 L服务器：适用于 MS SQL、 ODBC、 Oracle （两层）、 DB2 CLI、</p>
<p>.Sybase Ctlib、 Sybase Dblib、 Windows Sockets 和 DNS 协议。</p>
<ol>
<li>自定义：适用于 C 模板、 Visual Basic 模板、 Java 模板、 Javascript 和</li>
</ol>
<p>VBscript 类型脚本。</p>
<ol>
<li>分布式组件：适用于 COM/DCOM、 Corba-Java 和 Rmi -Java 协议。</li>
</ol>
<p>3. 电子商务：适用于 FTP、 LDAP、 Palm、 SOAP、 Web (HTTP/HTML) 和双</p>
<p>Web/Winsocket 协议。</p>
<ol>
<li>enterprise java bean：适用于 EJB 测试和 Rmi-Java 协议。</li>
<li>erp/crm：适用于 Baan、Oracle NCA、Peoplesoft-Tuxedo、Peoplesoft 8</li>
</ol>
<p>Wereb 多语言、 SAPGUI、 SAP-Web 和 Siebel （Siebel-DB2CLI、 Siebel-</p>
<p>MSSQL、 Siebel-Web 和 Siebel-Oracle）协议。</p>
<ol>
<li>传统：适用于终端仿真 (RTE)。</li>
<li>邮件服务：Internet 邮件访问协议 (IMAP)、 MS Exchange (MAPI)、 POP3</li>
</ol>
<p>和 SMTP。</p>
<ol>
<li>  中间件： Jacada 和 Tuxedo （6、 7）协议。</li>
<li>  流：适用于 MediaPlayer 和 RealPlayer 协议。</li>
<li>  无线：适用于 i-Mode、 VoiceXML 和 WAP 协议。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3280</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>浅谈web项目的数据库测试方法</title>
		<link>http://www.code365.org/?p=3278</link>
		<comments>http://www.code365.org/?p=3278#comments</comments>
		<pubDate>Tue, 01 May 2012 03:29:42 +0000</pubDate>
		<dc:creator>冰冰</dc:creator>
				<category><![CDATA[测试技术]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3278</guid>
		<description><![CDATA[  1、数据库测试分类 数据库的测试有很多分类，以下介绍几个比较常用的数据库测试： 单元测试 单元测试侧重于逻辑覆盖，相对对于复杂的代码来说，数据库开发的单元测试相对简单些，可以通过语句覆盖和走读的方式完成系统测试相对来说比较困难，这要求有很高的数据库设计能力和丰富的数据库测试经验。而集成测试和单元测试就相对简单了。  集成测试 　　集成测试是主要针对接口进行的测试工作，从数据库的角度来说和普通测试稍微有些区别对于数据库测试来说，需要考虑的是： 　　数据项的修改操作； 　　数据项的增加操作； 　　数据项的删除操作； 　　数据表增加满； 　　数据表删除空； 　　删除空表中的记录； 　　数据表的并发操作； 　　针对存储过程的接口测试； 　　结合业务逻辑做关联表的接口测试； 　　同样我们需要对这些接口考虑采用等价类、边界值、错误猜测等方法进行测试。 系统测试 传统软件系统测试的测试重点是需求覆盖，而对于我们的数据库测试同样也需要对需求覆盖进行保证。那么数据库在初期设计中也需要对这个进行分析,测试.例如存储过程，视图，触发器，约束，规则等我们都需要进行需求的验证确保这些功能设计是符合需求的.另一方面我们需要确认数据库设计文档和最终的数据库相同，当设计文档变化时我们同样要验证改修改是否落实到数据库上。这个阶段我们的测试主要通过数据库设计评审来实现。 &#160; 数据库性能 　　虽然我们的硬件最近几年进步很快，但是我们需要处理的数据以更快的速度在增加。几亿条记录的表格在现在是司空见惯的，如此庞大的数据量在大量并发连接操作时，我们不能像以前一样随意的使用查询，连接查询，嵌套查询，视图，这些操作如果不当会给系统带来非常巨大的压力，严重影响系统性能。性能优化分4部分：物理存储方面；.逻辑设计方面；数据库的参数调整；SQL语句优化 　　通过数据库系统的SQL语句分析工具，我们可以分析得到数据库语句执行的瓶颈，从而优化SQL语句。 安全测试 　　软件日益复杂，而数据又成为了系统中重中之重的核心，从以往对系统的破坏现在更倾向于对数据的获取和破坏。而数据库的安全被提到了最前端。自从SQL 注入攻击被发现，冒失万无一失的数据库一下从后台变为了前台，而一旦数据库被攻破，整个系统也会暴露在黑客的手下，通过数据库强大的存储过程，黑客可以轻松的获得整个系统的权限。而SQL的注入看似简单缺很难防范，对于安全测试来说，如何防范系统被注入是测试的难点。业界也有相关的数据库注入检测工具，来帮助用户对自身系统进行安全检测。 　　对于这点来说业界也有标准，例如ISO IEC 21827，也叫做SSE CMM 3.0，是CMM和ISO的集成的产物，专门针对系统安全领域的另外一方面，数据库的健壮性，容错性和恢复能力也是我们测试的要点，我们也可以发现功能测试，性能测试，安全测试，是一个由简到繁的过程，也是数据库测试人员需要逐步掌握的技能，这也是以后公司对数据库测试人员的要求。 另外一方面，数据库的健壮性，容错性和恢复能力也是我们测试的要点。 我们也可以发现功能测试，性能测试，安全测试，是一个由简到繁的过程，也是数据库测试人员需要逐步掌握的技能，这也是以后公司对数据库测试人员的要求。 &#160; &#160; 2数据库测试工具 DBunit 　　一款开源的数据库功能测试框架，可以使用类似与Junit的方式对数据库的基本操作进行白盒的单元测试，对输入输出进行校验。 QTP 大名鼎鼎的自动测试工具，通过对对象的捕捉识别，我们可以通过QTP来模拟用户的操作流程，通过其中的校验方法或者结合数据库后台的监控对整个数据库中的数据进行测试。个人觉得比较偏向灰盒。 &#8230; <a href="http://www.code365.org/?p=3278">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p style="text-align: left" align="center"> </p>
<h1>1、数据库测试分类</h1>
<p>数据库的测试有很多分类，以下介绍几个比较常用的数据库测试：</p>
<p><strong>单元测试</strong><strong></strong></p>
<p>单元测试侧重于逻辑覆盖，相对对于复杂的代码来说，数据库开发的单元测试相对简单些，可以通过语句覆盖和走读的方式完成系统测试相对来说比较困难，这要求有很高的数据库设计能力和丰富的数据库测试经验。而集成测试和单元测试就相对简单了。</p>
<p> <strong>集成测试</strong><strong></strong></p>
<p>　　集成测试是主要针对接口进行的测试工作，从数据库的角度来说和普通测试稍微有些区别对于数据库测试来说，需要考虑的是：</p>
<p>　　数据项的修改操作；</p>
<p>　　数据项的增加操作；</p>
<p>　　数据项的删除操作；</p>
<p>　　数据表增加满；</p>
<p>　　数据表删除空；</p>
<p>　　删除空表中的记录；</p>
<p>　　数据表的并发操作；</p>
<p>　　针对存储过程的接口测试；</p>
<p>　　结合业务逻辑做关联表的接口测试；</p>
<p>　　同样我们需要对这些接口考虑采用等价类、边界值、错误猜测等方法进行测试。</p>
<p><strong>系统测试</strong><strong></strong></p>
<p>传统软件系统测试的测试重点是需求覆盖，而对于我们的数据库测试同样也需要对需求覆盖进行保证。那么数据库在初期设计中也需要对这个进行分析,测试.例如存储过程，视图，触发器，约束，规则等我们都需要进行需求的验证确保这些功能设计是符合需求的.另一方面我们需要确认数据库设计文档和最终的数据库相同，当设计文档变化时我们同样要验证改修改是否落实到数据库上。这个阶段我们的测试主要通过数据库设计评审来实现。</p>
<p>&nbsp;</p>
<p><strong>数据库性能</strong><strong></strong></p>
<p>　　虽然我们的硬件最近几年进步很快，但是我们需要处理的数据以更快的速度在增加。几亿条记录的表格在现在是司空见惯的，如此庞大的数据量在大量并发连接操作时，我们不能像以前一样随意的使用查询，连接查询，嵌套查询，视图，这些操作如果不当会给系统带来非常巨大的压力，严重影响系统性能。性能优化分4部分：物理存储方面；.逻辑设计方面；数据库的参数调整；SQL语句优化</p>
<p>　　通过数据库系统的SQL语句分析工具，我们可以分析得到数据库语句执行的瓶颈，从而优化SQL语句。</p>
<p><strong>安全测试</strong><strong></strong></p>
<p>　　软件日益复杂，而数据又成为了系统中重中之重的核心，从以往对系统的破坏现在更倾向于对数据的获取和破坏。而数据库的安全被提到了最前端。自从SQL 注入攻击被发现，冒失万无一失的数据库一下从后台变为了前台，而一旦数据库被攻破，整个系统也会暴露在黑客的手下，通过数据库强大的存储过程，黑客可以轻松的获得整个系统的权限。而SQL的注入看似简单缺很难防范，对于安全测试来说，如何防范系统被注入是测试的难点。业界也有相关的数据库注入检测工具，来帮助用户对自身系统进行安全检测。</p>
<p>　　对于这点来说业界也有标准，例如ISO IEC 21827，也叫做SSE CMM 3.0，是CMM和ISO的集成的产物，专门针对系统安全领域的另外一方面，数据库的健壮性，容错性和恢复能力也是我们测试的要点，我们也可以发现功能测试，性能测试，安全测试，是一个由简到繁的过程，也是数据库测试人员需要逐步掌握的技能，这也是以后公司对数据库测试人员的要求。</p>
<p>另外一方面，数据库的健壮性，容错性和恢复能力也是我们测试的要点。</p>
<p>我们也可以发现功能测试，性能测试，安全测试，是一个由简到繁的过程，也是数据库测试人员需要逐步掌握的技能，这也是以后公司对数据库测试人员的要求。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1>2数据库测试工具</h1>
<p>DBunit</p>
<p>　　一款开源的数据库功能测试框架，可以使用类似与Junit的方式对数据库的基本操作进行白盒的单元测试，对输入输出进行校验。</p>
<p>QTP</p>
<p>大名鼎鼎的自动测试工具，通过对对象的捕捉识别，我们可以通过QTP来模拟用户的操作流程，通过其中的校验方法或者结合数据库后台的监控对整个数据库中的数据进行测试。个人觉得比较偏向灰盒。</p>
<p>&nbsp;</p>
<p>DataFactory</p>
<p>一款优秀的数据库数据自动生成工具，通过它你可以轻松的生成任意结构数据库，对数据库进行填充，帮助你生成所需要的大量数据从而验证我们数据库中的功能是否正确。这是属于黑盒测试。</p>
<p>LoadRunner</p>
<p>　　可以通过对协议的编程来对数据库做压力测试，在分析台编写相应的代码，在控制台设定相应参数，可以在场景中模拟数据库并发测试以及压力测试等。</p>
<p>Swingbench（这是一个重量级别的feature，类似LR，而且非常强大，只不过专门针对oracle而已）</p>
<p>数据库厂商也意识到这点，例如：oracle11g已经提供了real application test，提供数据库性能测试，分析系统的应用瓶颈。</p>
<p>还有很多第三方公司开发了SQL语句优化工具来帮助你自动的进行语句。</p>
<p>&nbsp;</p>
<h1>3数据库测试方法</h1>
<h2>3.1数据库系统测试方法</h2>
<p><strong>1</strong><strong>、数据库的一致性</strong><strong></strong></p>
<p>首先，是对数据库基础数据结构的验证工作，即数据库脚本是否满足数据库设计说明书、是否满足行业标准，检查项包括：表名、字段名、数据类型、数据长度、数据精度、主外键约束等；</p>
<p>其次，数据库的一致性是指数据在数据库的各个表中是否一致。如，多表中同一字段的值是否一致。尤其是要注意对于同一数据是否存在多入口现象；</p>
<p>最后，要注意数据的修改和删除等操作，数据库中的同一数据是否能够同步更新，有主外键关系、归属关系的数据是否能够同步删除（如：上级数据删除，而下级数据仍然存在于数据库中，将形成垃圾数据，甚至因统计算法不同而造成系统输出错误的运算结果）；</p>
<p>&nbsp;</p>
<p><strong>2</strong><strong>、防止数据过多的冗余</strong><strong></strong></p>
<p>数据冗余在系统实现中是不可避免的问题，有时会为了提高系统的运行效率或降低复杂度而人为的增加数据冗余；但如果冗余过大，将严重影响系统性能以及增加破坏数据一致性的风险；</p>
<p>&nbsp;</p>
<p><strong>3</strong><strong>、数据安全性</strong><strong></strong></p>
<p>数据安全性分为两种，其一，指在正常的业务操作中，是否会出现误删、误修改数据的情况；其二，是否存在数据的非法访问，包括业务逻辑的权限限制以及数据库用户的权限限制问题；尤其是黑客通过SQL注入绕过身份验证，从而对数据库进行修改或替换等操作，会严重影响系统的运行。</p>
<p>&nbsp;</p>
<p><strong>4</strong><strong>、大数据量测试</strong><strong></strong></p>
<p>主要考虑在大数据量的情况下，是否会出现数据丢失，事物是否回滚，数据一致性能否得到保障，系统响应时间等问题；</p>
<p>&nbsp;</p>
<p><strong>5</strong><strong>、针对数据存储、数据中间结果的验证</strong><strong></strong></p>
<p>面对复杂的系统，往往数据处理不是一步到位的，而是通过多个步骤，分布计算存储，这时就要去验证数据是否按照设计要求存放在指定位置，是否正确，有无缺失，中间结果是否能够按设计要求生成并存储等；</p>
<p>&nbsp;</p>
<p><strong>6</strong><strong>、结合业务逻辑验证数据库的合理性</strong><strong></strong></p>
<p>主要包括，数据类型、长度、精度是否满足业务需要，各种标示性字段，是否能够按照设计要求判别等；</p>
<p>&nbsp;</p>
<p><strong>7</strong><strong>、数据库的性能测试</strong><strong></strong></p>
<p>主要包括数据库的物理调优，索引类型是否合理、各种语句的优化、数据的存储应用能否按照业务使用频率以及业务逻辑规则而设计等等，这条需要有深厚的数据库应用及设计分析能力。</p>
<p>&nbsp;</p>
<h2>3.2 数据库完整性及输出错误测试方法</h2>
<p>数据库测试包括测试实际数据(内容)以及数据完整性,已经确保数据没有被误用以及规划的正确性,同时也对数据库应用(例如,Sql处理组件)进行功能性测试.通常会用到SqL脚本进行数据库测试.尽管不是所有的数据库都是适合Sql的,但是通过Sql数据库可以支持绝大部分数据操作,大多数的Web应用程序也是如此。</p>
<p>通常有两类由数据库错误引发的问题，它们是数据完整性错误以及输出错误。输出错误是在数据提取和操作数据指令过程中发生的错误引起的，这时源数据是正确的。</p>
<p>通常，数据操作包含了以下一些活动：</p>
<p>1.连接数据库  2.执行Sql语句、存储过程以及触发器  3.释放与数据库的连接</p>
<p>在数据库活动中所包含的错误主要有以下几种常见类型：</p>
<p>1.连接数据库失败，引起该类失败的许多潜在问题包括：</p>
<p>a.非法的用户名、密码或两者皆非法  b.对于某些数据活动，如创建表和存储过程，用户拥有不适当的权限。c.非法或错误的DSN  d.与拥有必要的DSN文件的服务器连接失败</p>
<p>指令（存储过程、触发器等）中常见错误包括：</p>
<p>1.数据库被配置为区分大小写的，但是代码却没有</p>
<p>2.在Sql语句中使用了保留关键字，例如 Select user from mytable。user为保留关键字</p>
<p>3.NULL被传递给不接受NULL的记录字段</p>
<p>4.在字符串字段中对单引号（‘）的错误处理。</p>
<p>5.在整型字段中对逗号（，）的错误处理。</p>
<p>6.数值对于字段大小来说过大，字符串对于字段的长度来说过长。</p>
<p>7.超时&#8212;数据库执行完某个过程所用时间长于脚本中所设定的超时值。</p>
<p>8.非法或错误拼写的字段、列、表或者视图的名称，未定义的字段、表或视图的名称，非法或错误拼写的存储过程名称</p>
<p>9.调用错误的存储过程。</p>
<p>10.缺少关键字。</p>
<p>&nbsp;</p>
<h2>3.3 数据库并发测试方法</h2>
<p><strong>1. </strong><strong>利用测试工具模拟多个最终用户进行并发测试;</strong></p>
<p>这种测试方法的缺点：最终用户往往并不是直接连接到数据库上，而是要经过一个和多个中间服务程序，所以并不能保证访问数据库时还是并发。其次，这种测试方法需要等到客户端程序、服务端程序全部完成才能进行;</p>
<p><strong>2. </strong><strong>利用测试工具编写脚本，直接连接数据库进行并发测试;</strong></p>
<p>这种方法可以有效的保证并发操作，而且在数据库访问程序完成即可测试，可以大大缩短测试时间，而且测试效果更好。在之后的项目实践中将运用到这种方法对项目进行并发测试。</p>
<p>&nbsp;</p>
<p><strong>数据库方面的测试执行：</strong><strong></strong></p>
<p>首先是查询优化表单，这是工作量最大的一个步骤，需要查询后台数据库几乎所有的表单，根据之前提取的需求点，在执行时需要注意：表、视图、索引名是否合法；字段名是否有保留字符；一些特殊符号（逗号，单引号等）的运用是否合法；NULL是否传递给非空字段。</p>
<p>其次是前台的内容变动对后台数据库的影响。</p>
<p>前台添加相关栏目，后台数据库是否生成相应的字段内容</p>
<p>后台相关数据变更，数据库字段是否也随之改变</p>
<p>&nbsp;</p>
<p>如上图在核心模块中添加顶级栏目，名称为：天气预报，成功添加后查询后台数据库相关表单，得到如下信心：</p>
<p>&nbsp;</p>
<p>前台会员注册信息：</p>
<p>&nbsp;</p>
<p>后台数据库表单查询：</p>
<p>&nbsp;</p>
<p>数据库安全测试：</p>
<p>利用SQL注入，绕过用户身份验证。例如编写脚本</p>
<p>string strName = Request["name"].ToString();</p>
<p>string strPSD = Request["password"].ToString();</p>
<p>string strSQL = “select * from dede_member  where name=&#8217;” + strName + “&#8216;and password=&#8217;” + strPSD + “&#8216;”;</p>
<p>返回记录条数大于0，则身份验证成功。但织梦系统后台数据库的密码是经过加密的，因此对于数据的安全性还是比较有保障的。</p>
<p>数据库并发测试：</p>
<p>首先编写脚本创建表testtable创建存储过程test：</p>
<p>if exists (select * from dbo.sysobjects where id = object_id(N&#8217;[dbo].[Test]&#8216;) and OBJECTPROPERTY(id, N&#8217;IsProcedure&#8217;) = 1)</p>
<p>drop procedure [dbo].[Test]</p>
<p>GO</p>
<p>if exists (select * from dbo.sysobjects where id = object_id(N&#8217;[dbo].[testtable]&#8216;) and OBJECTPROPERTY(id, N&#8217;IsUserTable&#8217;) = 1)</p>
<p>drop table [dbo].[testtable]</p>
<p>GO</p>
<p>CREATE TABLE [dbo].[testtable] (</p>
<p>[testid] [int] NULL ,</p>
<p>[counts] [int] NULL</p>
<p>) ON [PRIMARY]</p>
<p>GO</p>
<p>insert into testtable (testid,counts) values (1,0)</p>
<p>GO</p>
<p>SET QUOTED_IDENTIFIER ON</p>
<p>GO</p>
<p>SET ANSI_NULLS ON</p>
<p>GO</p>
<p>CREATE Procedure dbo.Test</p>
<p>as</p>
<p>declare @count int</p>
<p>begin tran TEST</p>
<p>select @count=countsfrom testtable where testid=1</p>
<p>update testtable setcounts=@count+1</p>
<p>if (@@error &gt;0) begin</p>
<p>rollback tran TEST</p>
<p>end else begin</p>
<p>commit tran TEST</p>
<p>end</p>
<p>GO</p>
<p>SET QUOTED_IDENTIFIER OFF</p>
<p>GO</p>
<p>SET ANSI_NULLS ON</p>
<p>GO</p>
<p>然后创建测试脚本：</p>
<p>#include</p>
<p>{push Timeout_scale = 200; /* Set timeouts to 200% of maximum response time */</p>
<p>push Think_def = “LR”;</p>
<p>Min_tmout = 120000; /* Set minimum Timeout_val to 2 minutes*/</p>
<p>push Timeout_val = Min_tmout;</p>
<p>ser=sqlconnect(“server”,”admin”,”admin”,”192.168.3.187&#8243;,”sqlserver”);</p>
<p>set Server_connection = ser;</p>
<p>push Think_avg = 0;</p>
<p>sync_point “logon”;</p>
<p>sqlexec ["sql_1000"] “testdb..test”;</p>
<p>sqldisconnect (ser);</p>
<p>}</p>
<p>然后测试执行：</p>
<p>运行上一步创建的脚本(运行时自动创建Suite)，在Run Suite窗口中的”Number of users”上输入20。运行完脚本，打开数据库查看counts的数值。把counts值改为零多次运行脚本，观察每次运行后counts的结果。</p>
<p>测试说明：</p>
<p>1. 测试示例程序的目的是，存储过程test每执行一次，表testtable中的counts字段增加一;</p>
<p>2. 第三步的测试可以发现每次执行后counts结果并不相同，而且不等于20，这说明这个程序是在并发时是问题的;</p>
<p>3. 将存储过程中的select @count=countsfrom testtable where testid=1修改为select @count=countsfrom testtable with (UPDLOCK) where testid=1。再次进行并发测试，每次的结果应该都是20。</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3278</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>对Apache配置的一些安全方法</title>
		<link>http://www.code365.org/?p=3274</link>
		<comments>http://www.code365.org/?p=3274#comments</comments>
		<pubDate>Mon, 30 Apr 2012 08:37:19 +0000</pubDate>
		<dc:creator>阿囧</dc:creator>
				<category><![CDATA[互联网安全]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3274</guid>
		<description><![CDATA[by HUC.Tiger 前几天在红盟群里发了一个关于apache死循环的讨论，最后由群里yaya及lip等给予了一些提示法则，呵呵，回去之后搞定了，困扰我公司几个月的事情总算解决，今天我特地发一下关于一些apache安全配置的一些问题. 1、隐藏Apache的版本号及其它敏感信息 默认情况下，很多Apache安装时会显示版本号及操作系统版本，甚至会显示服务器上安装的是什么样的Apache模块。这些信息可以为黑客所用，并且黑客还可以从中得知你所配置的服务器上的很多设置都是默认状态。 这里有两条语句，你需要添加到你的httpd.conf文件中： ServerSignature Off ServerTokens Prod ServerSignature出现在Apache所产生的像404页面、目录列表等页面的 底部。ServerTokens目录被用来判断Apache会在Server HTTP响应包的头部填充什么信息。如果把ServerTokens设为Prod，那么HTTP响应包头就会被设置成： Server：Apache 如果你非常想尝试其它事物，你可以通过编辑源代码改成不是Apache的其它东西，或者你可以通过下面将要介绍的mod_security实现。 二、确保Apache以其自身的用户账号和组运行 有的Apache安装过程使得服务器以nobody的用户运行，所以，假定Apache和你的邮件服务器都是以nobody的账号运行的，那么通过Apache发起的攻击就可能同时攻击到邮件服务器，反之亦然。 User apache Group apache 三、确保web根目录之外的文件没有提供服务 我们不让Apache访问web根目录之外的任何文件。假设你的所以web站点文件都放在一个目录下（例如/web），你可以如下设置： Order Deny,Allow Deny from all Options None AllowOverride None Order Allow,Deny Allow from all 注意，因为我们设置Opitins None 和AllowOverride &#8230; <a href="http://www.code365.org/?p=3274">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>by HUC.Tiger<br />
前几天在红盟群里发了一个关于apache死循环的讨论，最后由群里yaya及lip等给予了一些提示法则，呵呵，回去之后搞定了，困扰我公司几个月的事情总算解决，今天我特地发一下关于一些apache安全配置的一些问题.</p>
<p>1、隐藏Apache的版本号及其它敏感信息<br />
默认情况下，很多Apache安装时会显示版本号及操作系统版本，甚至会显示服务器上安装的是什么样的Apache模块。这些信息可以为黑客所用，并且黑客还可以从中得知你所配置的服务器上的很多设置都是默认状态。<span id="more-3274"></span><br />
这里有两条语句，你需要添加到你的httpd.conf文件中：<br />
ServerSignature Off<br />
ServerTokens Prod<br />
ServerSignature出现在Apache所产生的像404页面、目录列表等页面的 底部。ServerTokens目录被用来判断Apache会在Server HTTP响应包的头部填充什么信息。如果把ServerTokens设为Prod，那么HTTP响应包头就会被设置成：<br />
Server：Apache<br />
如果你非常想尝试其它事物，你可以通过编辑源代码改成不是Apache的其它东西，或者你可以通过下面将要介绍的mod_security实现。<br />
二、确保Apache以其自身的用户账号和组运行<br />
有的Apache安装过程使得服务器以nobody的用户运行，所以，假定Apache和你的邮件服务器都是以nobody的账号运行的，那么通过Apache发起的攻击就可能同时攻击到邮件服务器，反之亦然。<br />
User apache<br />
Group apache<br />
三、确保web根目录之外的文件没有提供服务<br />
我们不让Apache访问web根目录之外的任何文件。假设你的所以web站点文件都放在一个目录下（例如/web），你可以如下设置：<br />
Order Deny,Allow<br />
Deny from all<br />
Options None<br />
AllowOverride None</p>
<p>Order Allow,Deny<br />
Allow from all</p>
<p>注意，因为我们设置Opitins None 和AllowOverride None，这将关闭服务器的所有Option和Override。你现在必须明确把每个目录设置成Option或者Override。<br />
四、关闭目录浏览<br />
你可以在Directory标签内用Option命令来实现这个功能。设置Option为None或者－Indexes。<br />
Options -Indexes<br />
五、关闭includes<br />
这也可以通过在Directory标签内使用Option命令来实现。设置Option为None或者－Includes。<br />
Options -Includes<br />
六、关闭CGI执行程序<br />
如果你不用CGI，那么请把它关闭。在目录标签中把选项设置成None或-ExecCGI就可以：<br />
Options -ExecCGI<br />
七、禁止Apache遵循符号链接<br />
同上，把选项设置成None或-FollowSymLinks：<br />
Options -FollowSymLinks<br />
八、关闭多重选项<br />
如果想关闭所有选项，很简单：<br />
Options None<br />
如果只想关系一些独立的选项，则通过将Options做如下设置可实现：<br />
Options -ExecCGI -FollowSymLinks -Indexes<br />
九、关闭对.htaccess文件的支持<br />
在一个目录标签中实现：<br />
AllowOverride None<br />
如果需要重载，则保证这些文件不能够被下载，或者把文件名改成非.htaccess文件。比如，我们可以改成.httpdoverride文件，然后像下面这样阻止所有以.ht打头的文件：<br />
AccessFileName .httpdoverride<br />
Order allow,deny<br />
Deny from all<br />
Satisfy All<br />
十、运行mod_security<br />
Run mod_security是O’Reilly出版社出版的Apache Security一书的作者，Ivan Ristic所写的一个非常好用的一个Apache模块。可以用它实现以下功能：<br />
·简单过滤<br />
·基于过滤的常规表达式<br />
·URL编码验证<br />
·Unicode编码验证<br />
·审计<br />
·空字节攻击防止<br />
·上载存储限制<br />
·服务器身份隐藏<br />
·内置的Chroot支持<br />
·更多其它功能<br />
十一、关闭任何不必要的模块<br />
Apache通常会安装几个模块，浏览Apache的module documentation，了解已安装的各个模块是做什么用的。很多情况下，你会发现并不需要激活那些模块。<br />
找到httpd.conf中包含LoadModule的代码。要关闭这些模块，只需要在代码行前添加一个#号。要找到正在运行的模块，可以用以下语句：<br />
grep LoadModule httpd.conf<br />
以下模块通常被激活而并无大用：mod_imap, mod_include, mod_info, mod_userdir, mod_status, mod_cgi, mod_autoindex。<br />
十二、确定只有 才能root访问apache的config和binaries<br />
假如你的apache装在/usr/local/apache<br />
chown -R root:root /usr/local/apache<br />
chmod -R o-rwx /usr/local/apache<br />
十三、降低timeout值（Lower the Timeout value）<br />
默认的timeout被设定为300s,为了帮助减少拒绝服务攻击的潜在影响，你可以如下设置：<br />
Timeout 45<br />
十四、Limiting large requests<br />
apache有很多指令可以让你限制请求包的大小，对减轻拒绝服务攻击的影响很有效。<br />
其中一条就是运行LimitRequestBody指令。这个指令默认设置为无限制 。如果你<br />
只允许上传的文件在1MB以内，你可以如下设置：<br />
LimitRequestBody 1048576<br />
如果你不允许文件上传，你可以把它设置的更小！<br />
其他的指令如：LimitRequestFields, LimitRequestFieldSize 和 LimitRequestLine.<br />
对多数服务器来说，这些指令都被设置了一个适当的默认值。但你可以为了你的需要而改变他们的默认设置！<br />
十五、Limiting the size of an XML Body<br />
如果你运行了模块mod_dav，那么你可能需要限制XML request body的大小。LimitXMLRequestBody 是apache2上仅有的有效指令，他的默认值是1百万字节（近1MB）<br />
也有许多设置为0 ，意味着无限制大小，当你使用WebDAV上传巨型文件时，这种设置可能很有用，但是如果你只是简单的为了来源控制，你可能需要设置一个上限，如10MB：<br />
LimitXMLRequestBody 10485760<br />
十六、Limiting Concurrency<br />
apache有许多的配置设定来调节处理concurrent request<br />
MaxClients是服务于请求的child processes 最大限制数。很可能设置的太高而没有足够的内存去处理海量并发请求。<br />
其他的指令有：MaxSpareServers, MaxRequestsPerChild<br />
在apache2中<br />
调节ThreadsPerChild, ServerLimit和MaxSpareThreads来匹配你的操作系统和硬件是非常重要的！</p>
<p>十七、Restricting Access by IP<br />
如果你只想让某个网段或者某个IP接入，你可以在apache配置文件中强制实行。<br />
如：你想限制你的intranet，只能被176.16.网段接入：<br />
Order Deny,Allow<br />
Deny from all<br />
Allow from 176.16.0.0/16<br />
Or by IP:<br />
Order Deny,Allow<br />
Deny from all<br />
Allow from 127.0.0.1</p>
<p>十八、Adjusting KeepAlive settings<br />
按照Apache的文档，使用HTTP Keep Alive&#8217;s 你能提升客户端50％的性能。因此，改变这些设置之前你得小心一点，你将为了缓解一点点的Dos攻击而牺牲掉性能。<br />
KeepAlive&#8217;s默认设置为on,你应该别动它。<br />
但你可以考虑去改变MaxKeepAliveRequests的值，它的默认值为100，和改变KeepAliveTimeout的值，默认值为15。通过分析你的日志来指定一个合理的值。</p>
<p>十九、Run Apache in a Chroot environment<br />
chroot 允许你在一个隔离的jail子系统中运行一个程序。这避免了让它影响这台服务器上的其他服务。<br />
上面提到的mod_security模块内置了chroot的支持。<br />
很简单，在你的配置文件中添加一条mod_security指令。（前提是你得安装mod_security）</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3274</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP调试技术手册发布(1.0.0 pdf)</title>
		<link>http://www.code365.org/?p=3269</link>
		<comments>http://www.code365.org/?p=3269#comments</comments>
		<pubDate>Mon, 30 Apr 2012 08:32:16 +0000</pubDate>
		<dc:creator>阿囧</dc:creator>
				<category><![CDATA[WEB开发]]></category>
		<category><![CDATA[互联网安全]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3269</guid>
		<description><![CDATA[•作者: laruence(http://www.laruence.com) •本文地址: http://www.laruence.com/2010/06/21/1608.html •转载请注明出处 黑夜路人前段时 间, 本着分享/总结的精神, 计划要总结下PHP常用的调试技术, 就一些问题找到了我.. 如今第一版的PHP调试技术手册已经发布. 冠以我名, 我甚感惶恐, 只能一并赞下小黑的nice了~ 下载地址: http://heiyeluren-doc.googlecode.com/files/PHP-Debug-Manual-public.pdf 备份下载地址：http://www.code365.org/wp-content/uploads/2012/04/PHP-Debug-Manual-public.pdf 目录: 1 内置API输出调试 1.1 基本调试API 1.1.1 echo (print): 1.1.2 printf 1.1.3 print_r、var_dump(var_export)、debug_zval_dump 1.2 错误控制和日志记录调试 1.2.1 错误选项控制 1.2.2 错误抛出和处理 1.2.3 使用错误抑制符 1.2.4 日志记录 2 &#8230; <a href="http://www.code365.org/?p=3269">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>•作者: laruence(<a href="http://www.laruence.com/">http://www.laruence.com</a>)<br />
•本文地址: <a href="http://www.laruence.com/2010/06/21/1608.html">http://www.laruence.com/2010/06/21/1608.html</a><br />
•转载请注明出处<br />
黑夜路人前段时 间, 本着分享/总结的精神, 计划要总结下PHP常用的调试技术, 就一些问题找到了我..</p>
<p>如今第一版的PHP调试技术手册已经发布.</p>
<p>冠以我名, 我甚感惶恐, 只能一并赞下小黑的nice了~<span id="more-3269"></span></p>
<p>下载地址: <a href="http://heiyeluren-doc.googlecode.com/files/PHP-Debug-Manual-public.pdf">http://heiyeluren-doc.googlecode.com/files/PHP-Debug-Manual-public.pdf</a><br />
备份下载地址：<a href="http://www.code365.org/wp-content/uploads/2012/04/PHP-Debug-Manual-public.pdf">http://www.code365.org/wp-content/uploads/2012/04/PHP-Debug-Manual-public.pdf</a></p>
<p>目录:</p>
<p>1 内置API输出调试<br />
1.1 基本调试API<br />
1.1.1 echo (print):<br />
1.1.2 printf<br />
1.1.3 print_r、var_dump(var_export)、debug_zval_dump<br />
1.2 错误控制和日志记录调试<br />
1.2.1 错误选项控制<br />
1.2.2 错误抛出和处理<br />
1.2.3 使用错误抑制符<br />
1.2.4 日志记录<br />
2 浏览器调试<br />
2.1 页面输出调试<br />
2.2 FirePHP  调试<br />
2.2.1 普通变量监测<br />
2.2.2 调用栈监测<br />
2.2.3 监测抛出异常<br />
2.2.4 组显示信息<br />
3 IDE 调试<br />
3.1 基本常用IDE介绍<br />
3.1.1 Vim<br />
3.1.2 Zend Studio<br />
3.1.3 Eclipse<br />
3.1.4 NetBeans<br />
3.2 IDE调试<br />
3.2.1 Zend Studio + Zend Debugger<br />
3.2.2 Eclipse (PDT) + Xdebug<br />
3.2.3 Vim + Xdebug + DBGp<br />
4 PHP 性能调试技术<br />
4.1 基本时间占用监测<br />
4.2 使用  Xdebug 进行性能分析<br />
4.2.1 安装配置：<br />
4.3 APD(Advanced PHP Debugger)<br />
4.3.1 安装配置<br />
4.3.2 使用APD<br />
4.4 使用Xhprof 进行性能分析<br />
4.4.1 Xhprof  的优点：<br />
5 PHP单元测试技术<br />
5.1 PHPUnit</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3269</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>深掘XSS漏洞场景之XSS Rootkit</title>
		<link>http://www.code365.org/?p=3267</link>
		<comments>http://www.code365.org/?p=3267#comments</comments>
		<pubDate>Mon, 30 Apr 2012 08:14:39 +0000</pubDate>
		<dc:creator>阿囧</dc:creator>
				<category><![CDATA[互联网安全]]></category>

		<guid isPermaLink="false">http://www.code365.org/?p=3267</guid>
		<description><![CDATA[0&#215;00 前言   众所周知xss漏洞的风险定义一直比较模糊，XSS漏洞属于高危漏洞还是低风险漏洞一直以来都有所争议。XSS漏洞类型主要分为两种持久型和非持久型：   1. 非持久型XSS漏洞一般存在于URL参数中，需要访问黑客构造好的特定URL才能触发漏洞。   2. 持久型XSS漏洞一般存在于富文本等交互功能，如发帖留言等，黑客可以用XSS内容经正常功能进入数据库持久保存。 3. DOM XSS漏洞，也分为持久和非持久型两种，多是通过javascript DOM接口获取地址栏、referer或编码指定HTML标签内容造成。   一般持久型XSS漏洞比非持久型XSS漏洞风险等级高，从漏洞的本质上来说这是没错的，但漏洞的利用仍然需要看场景，有时候更深入的看待场景能够挖掘出意想不到的东西，大家接着往下看。   0&#215;01 漏洞场景解析   首先我给出一段PHP分页的XSS漏洞的简单代码：   demo.php————————————————————-  &#60;?php  foreach(Array(&#8216;_GET&#8217;,'_POST&#8217;,'_cookie&#8217;) as $_request)  {  foreach($$_request as $_k =&#62; $_v) ${$_k} = $_v;  }  ?&#62;   &#60;a &#8230; <a href="http://www.code365.org/?p=3267">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>0&#215;00 前言<br />
 <br />
众所周知<a href="http://neeao.com/tag/xss/">xss</a>漏洞的风险定义一直比较模糊，XSS漏洞属于高危漏洞还是低风险漏洞一直以来都有所争议。XSS漏洞类型主要分为两种持久型和非持久型：<br />
 <br />
1. 非持久型XSS漏洞一般存在于URL参数中，需要访问黑客构造好的特定URL才能触发漏洞。<br />
 <br />
2. 持久型XSS漏洞一般存在于富文本等交互功能，如发帖留言等，黑客可以用XSS内容经正常功能进入数据库持久保存。</p>
<p>3. DOM XSS漏洞，也分为持久和非持久型两种，多是通过javascript DOM接口获取地址栏、referer或编码指定HTML标签内容造成。<br />
 <br />
一般持久型XSS漏洞比非持久型XSS漏洞风险等级高，从漏洞的本质上来说这是没错的，但漏洞的利用仍然需要看场景，有时候更深入的看待场景能够挖掘出意想不到的东西，大家接着往下看。<span id="more-3267"></span></p>
<p> <br />
0&#215;01 漏洞场景解析<br />
 <br />
首先我给出一段PHP分页的XSS漏洞的简单代码：<br />
 <br />
demo.php————————————————————-<br />
 &lt;?php<br />
 foreach(Array(&#8216;_GET&#8217;,'_POST&#8217;,'_cookie&#8217;) as $_request)<br />
 {<br />
 foreach($$_request as $_k =&gt; $_v) ${$_k} = $_v;<br />
 }<br />
 ?&gt;<br />
 <br />
&lt;a href=”&lt;? echo $_SERVER["PHP_SELF"]; ?&gt;?i=&lt;? echo $id;?&gt;”&gt;分页&lt;/a&gt;<br />
 ———————————————————————<br />
 <br />
这段PHP代码中模拟register_globals是Web程序中常见的，代码中输出了网页的分页链接这个也是常见的，因为忽略了对传入数据的效验，更产生了最常见的XSS漏洞。<br />
 <br />
下面是这个XSS漏洞的验证方法：<br />
 http://127.0.0.1/demo.php?id=1&#8243;&gt;&lt;script&gt;alert(1)&lt;/script&gt;<br />
 <br />
GET方法在id参数中传入HTML内容，导致网页内容中的herf闭合，执行script标签里的脚本内容：<br />
 <br />
&lt;a href=”/demo.php?id=1&#8243;&gt;&lt;script&gt;alert(1)&lt;/script&gt;”&gt;分页&lt;/a&gt;<br />
 <br />
这是一个典型的非持久型XSS漏洞，在常规的思维逻辑下，这个漏洞到这里基本就打止了，本文也马上要变为普通的科普文了，然而事实并没有那么简单，这个漏洞场景再深入挖掘，就牵出了本文的重头戏。</p>
<p>0&#215;02 XSS Rootkit实现方法<br />
 <br />
我们知道操作系统有Rootkit这样的内核后门，Rootkit最大的特性之一就是隐蔽，普通的安全软件无法检测出系统中运作着Rootkit，以保证Rootkit后门能长久存活于系统中，而Web程序的漏洞很难达到这一效果，而我发现某些特定场景的XSS漏洞能够达到这一效果。</p>
<p>现今流行的PHP Web程序的都喜欢自己模拟register_globals（全局变量注册）这一特性，通过GET、POST、cookie等方法注册变量（本文下面的内容都简称GPC），通过GPC直接注册变量方便整个程序的运作，而本文的重点即是围绕这一点来展开的。</p>
<p>第一部分的我模拟的XSS漏洞即是一个典型的全局变量注册的场景，demo.php不仅可以GET传参，还能接受cookie传参，变量注册顺序是GPC，由于注册变量的流程是一个foreach循环，所以通过GP注册变量最后能被C覆盖，而cookie是客户端浏览器的持久化数据，如果通过XSS漏洞设置cookie，我们完全可以把这个典型的非持久型XSS漏洞变成持久的，说到这里大家一定感觉非常兴奋了，我就来实际测试一下：<br />
 <br />
先写出一段设置cookie的javascript代码<br />
 <br />
Persistence_data=&#8217;”&gt;&lt;script&gt;alert(/xss/)&lt;/script&gt;&#8217;;<br />
var date=new Date();<br />
var expireDays=365; //设置cookie一年后失效<br />
date.setTime(date.getTime()+expireDays*24*3600*1000);<br />
document.cookie=&#8217;id=&#8217;+Persistence_data+&#8217;;expires=&#8217;+date.toGMTString(); //设置cookie的id参数值为XSS代码<br />
 <br />
把设置cookie的javascript代码编码一次，放入XSS URL中，这样防止魔术引号和不同浏览器编码的未知情况影响我们的测试，关闭IE8/9等XSS筛选器后，我们访问下面的URL让XSS生效。<br />
 <br />
http://127.0.0.1/demo.php?id=1&#8243;&gt;&lt;script&gt;eval(String.fromCharCode(80,101,114,115,105,115,116,101,110,99,101,95,100,97,116,97,61,39,34,62,60,115,99,114,105,112,116,62,97,108,101,114,116,40,47,120,115,115,47,41,60,47,115,99,114,105,112,116,62,39,59,13,10,118,97,114,32,100,97,116,101,61,110,101,119,32,68,97,116,101,40,41,59,13,10,118,97,114,32,101,120,112,105,114,101,68,97,121,115,61,51,54,53,59,13,10,100,97,116,101,46,115,101,116,84,105,109,101,40,100,97,116,101,46,103,101,116,84,105,109,101,40,41,43,101,120,112,105,114,101,68,97,121,115,42,50,52,42,51,54,48,48,42,49,48,48,48,41,59,13,10,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,61,39,105,100,61,39,43,80,101,114,115,105,115,116,101,110,99,101,95,100,97,116,97,43,39,59,101,120,112,105,114,101,115,61,39,43,100,97,116,101,46,116,111,71,77,84,83,116,114,105,110,103,40,41,59))&lt;/script&gt;</p>
<p> <br />
结果令人非常满意，当我们关闭浏览器乃至关闭重启电脑后，再重新访问下面的网页：</p>
<p>无论是访问http://127.0.0.1/demo.php</p>
<p>还是访问http://127.0.0.1/demo.php?id=1</p>
<p>我们的XSS代码都会生效，同时如果客户端未清理cookie，这个XSS漏洞将有效一年的时间，达到了Rootkit隐蔽和能够持久存活的效果。</p>
<p>0&#215;03 XSS Rootkit实战</p>
<p>DEDECMS后台登陆主页的模板中有个gotopage变量存在XSS漏洞，代码如下：</p>
<p>dede\templets\login.htm</p>
<p>65行左右</p>
<p>&lt;input type=”hidden” name=”gotopage” value=”&lt;?php if(!empty($gotopage)) echo $gotopage;?&gt;” /&gt;</p>
<p>DEDECMS核心代码中，模拟全局变量注册机制的顺序是GPC，也就是C能够覆盖GP所注册的变量。</p>
<p>我们再套用0X02的代码测试，可以在cookie中持久化保存gotopage变量，如果管理员触发过我们的XSS漏洞，我们就能在管理员的cookie中持久化保存gotopage变量，将gotopage隐藏表单值变为我们的任意脚本内容，以后管理员只要是访问后台页面都会触发XSS漏洞，我们完全可以劫持管理员的整个登陆过程，悄无声息的直接获取管理员的密码。</p>
<p>当然DEDECMS这个漏洞的如何灵活运用更取决于黑客的发散思维，比如IE8/9等会拦截URL XSS，我们可以利用一个持久型的XSS或DOM XSS做为这类XSS Rootkit漏洞的payload,另外cookie的设置不限于同源策略,在任意子域名设置的cookie，可以让整个域名的应用都接受这个cookie,黑客可以脱离于DEDECMS程序本身的限制,在整个网站架构上的薄弱点攻击DEDECMS的后台。</p>
<p>0&#215;04 深入XSS Rootkit场景</p>
<p>在PHP全局变量注册机制的场景下，调整GPC的注册变量的顺序可以减弱XSS Rootkit攻击效果，如discuz程序：</p>
<p>foreach(array(&#8216;_COOKIE&#8217;, &#8216;_POST&#8217;, &#8216;_GET&#8217;) as $_request) {<br />
 foreach($$_request as $_key =&gt; $_value) {<br />
  $_key{0} != &#8216;_&#8217; &amp;&amp; $$_key = daddslashes($_value);<br />
 }<br />
}</p>
<p>注册变量的顺序是CPG，我们的C始终都不能覆盖GP所注册过的变量，不过程序的某个流程导致变量未初始化，还是能产生XSS Rootkit效果，如</p>
<p>http://xx.163.com/logging.php?action=logout&#038;referer=javascript:alert()&#038;formhash=rootkit</p>
<p>在DISCUZ程序的退出代码存在一个XSS漏洞，在用户没有登陆的情况下，退出代码中的referer变量没有初始化，导致我们能任意控制这个变量。</p>
<p>在这个情况下我们不用担心CPG的注册顺序问题，但我们需要构造特定的URL，造成变量未初始化的情况才能触发XSS漏洞，这样XSS Rootkit攻击效果就大打折扣了，用户在登陆后的正常退出操作是不能触发我们的XSS漏洞的，已脱离了XSS Rookit的优势。</p>
<p>另外一个场景是滥用request类变量的情况，在不同脚本和服务器环境中request类变量的效果可能不同，如在我之前的《浅谈绕过WAF的数种方法》提到了asp/asp .net等request类变量有复参特性，所以gpc的内容都能同时进入注册变量，也可能会产生XSS Rootkit漏洞的情况。</p>
<p>最后还有一类特殊的DOM XSS情况，80sec的成员疯狗在几年前发现过，某大型网站的主页读取COOKIE中的用户ID在网页中显示并没有进行HTML编码，导致一个XSS漏洞即可在主页中安装XSS Rookit。</p>
<p>当然还有更多的场景，在剑心的《web应用程序中的rootkit》也都有提过，XSS Rootkit的场景我就解读到这里了，更多的场景就留给大家思维发散了。</p>
<p> <br />
0&#215;05 后话</p>
<p>至此我们用非持久型XSS漏洞完成了一次到XSS Rootkit的转变，再一次揭示了漏洞的场景有多么重要，深掘漏洞场景完成一次本质的升华是多么美妙的事情。</p>
<p>程序员需要重视程序安全的每一个细节，任何一个不起眼的漏洞都可能会造成意想不到的危害。<br />
 <br />
一些web漏洞扫描器报告中提示非持久型XSS漏洞标为高危漏洞，普遍存在争议的情况，可以根据本文做参考，对场景再深入挖掘来定义风险，那么本文最重要的目的也就达到了。</p>
<p>0&#215;06 参考</p>
<p>跨站脚本漏洞导致的浏览器劫持攻击</p>
<p>http://www.80sec.com/browser-hijacking.html</p>
<p>web应用程序中的rootkit</p>
<p>http://www.80sec.com/webapp-rootki.html</p>
<p>浅谈绕过WAF的数种方法</p>
<p>http://www.80sec.com/%e6%b5%85%e8%b0%88%e7%bb%95%e8%bf%87waf%e7%9a%84%e6%95%b0%e7%a7%8d%e6%96%b9%e6%b3%95.html</p>
]]></content:encoded>
			<wfw:commentRss>http://www.code365.org/?feed=rss2&#038;p=3267</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

