﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-闲人野居-随笔分类-单元测试</title><link>http://www.blogjava.net/zyl/category/17750.html</link><description>好好学习，天天向上</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 20:02:06 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 20:02:06 GMT</pubDate><ttl>60</ttl><item><title>关于TestNG</title><link>http://www.blogjava.net/zyl/archive/2006/10/05/73468.html</link><dc:creator>布衣郎</dc:creator><author>布衣郎</author><pubDate>Thu, 05 Oct 2006 07:44:00 GMT</pubDate><guid>http://www.blogjava.net/zyl/archive/2006/10/05/73468.html</guid><wfw:comment>http://www.blogjava.net/zyl/comments/73468.html</wfw:comment><comments>http://www.blogjava.net/zyl/archive/2006/10/05/73468.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/zyl/comments/commentRss/73468.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zyl/services/trackbacks/73468.html</trackback:ping><description><![CDATA[
		<span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US">  </span>     TestNG是一个不错的测试框架，尤其是用于模块测试，以及大范围的测试。相对于JUnit来说，更为灵活。随着JUnit4的推出，很多功能都与TestNG相似，但相对于JUnit4，TestNG还是有很多部分是有区别的。<br />      TestNG的IDE支持也不错，对于Eclipse,Idea,Ant都有很好的支持。<br />      先来看一看怎么使用TestNG，当然首先需要下载TestNG包。目前的版本为5.1，下载地址如下：<br />      <a href="http://testng.org/doc/download.html">http://testng.org/doc/download.html</a> ，也可以下载相应的Eclipse插件。<br />      运行TestNG，可以从命令行或者IDE，或者Ant中运行。<br />      命令行：<br />     <b> 
java org.testng.TestNG -groups windows,linux -testclass org.test.MyTest<br />      </b>对于大型的测试，需要定义一个xml文件，一般为testng.xml。<br />    <br /><table border="0" cellpadding="0" cellspacing="0" height="172" width="741"><tbody><tr valign="top"><td width="10"><br /></td><td width="100%"><a name="code1"></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td><code></code><pre class="section">&lt;!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" &gt;<br /> <br /><span class="tag">&lt;suite</span><span class="attribute">name="Suite1"</span>    <span class="attribute">verbose="1"</span> &gt;<br /><span class="tag">&lt;test</span><span class="attribute">name="Nopackage"</span> &gt;<br /><span class="tag">&lt;classes&gt;<br /></span>       <span class="tag">&lt;class</span><span class="attribute">name="NoPackageTest"</span>  /&gt;<br /><span class="tag">&lt;/classes&gt;</span><br /><span class="tag">&lt;/test&gt;</span><br /><br /><span class="tag">&lt;test</span><span class="attribute">name="Regression1"</span>   &gt;<br /><span class="tag">&lt;classes&gt;<br /></span><span class="tag">&lt;class</span><span class="attribute">name="test.sample.ParameterSample"</span>  /&gt;<br /><span class="tag">&lt;class</span><span class="attribute">name="test.sample.ParameterTest"</span> /&gt;<br /><span class="tag">&lt;/classes&gt;<br /></span><span class="tag">&lt;/test&gt;<br />&lt;/suite&gt;</span></pre></td></tr></tbody></table></td></tr></tbody></table><b><br />     java org.testng.TestNG testng.xml<br />   </b>  当然如果使用Eclipse插件，就简单多了。<b><br /></b><br />      下面来看一下，如何来实现测试的，与JUnit4 差不多（怀疑，JUnit4是不是有抄袭TestNG的成分）。<br />      声明测试方法如下：<span style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;" lang="EN-US"><br /></span><table border="0" cellpadding="0" cellspacing="0" height="172" width="741"><tbody><tr valign="top"><td width="10"><br /></td><td width="100%"><a name="code1"><b></b></a><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td><code></code><pre class="section"><font color="#ff0000">  @Test</font><br />    public void testMethod1() {<br />        System.out.println("in testMethod1");<br />    }<br /><br /><font color="#ff0000">@Test</font><br />    public void testMethod2() {<br />        System.out.println("in testMethod2");<br />    }<br /></pre></td></tr></tbody></table></td></tr></tbody></table><br />     基本上都是采用java5的注释实现的。<br />     与JUnit4 不同在于，测试方法可以分组，它可以根据诸如运行时间这样的特征来对测试分类。<br /><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td><code></code><pre class="section"><font color="#ff0000">  @Test(groups={"fun1","fun2"})</font><br />    public void testMethod1() {<br />        System.out.println("in testMethod1");<br />    }<br /><br /><font color="#ff0000">@Test</font><font><font color="#ff0000">(groups={"fun1"})</font></font><br />    public void testMethod2() {<br />        System.out.println("in testMethod2");<br />    }</pre></td></tr></tbody></table><br />      同JUnit4 一样，同样支持Before,After方法，如同setUp 和tearDown,不过TestNG更为灵活，支持各种签名方式，如private,protected。<br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td><code></code>     <font color="#ff0000">@BeforeMethod</font><br />    protected void beforeMethod() {<br />        System.out.println("in beforeMethod");<br />    }<br /><br />    <font color="#ff0000">@AfterMethod</font><br />    protected void afterMethod() {<br />        System.out.println("in afterMethod");<br />    }<br /></td></tr></tbody></table><br />     同样也支持BeforeClass 和AfterClass，只执行一次的方法，但是可以不需要使用static签名<br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td>    <font color="#ff0000">@BeforeClass</font><br />    protected void beforeClassMethod() {<br />        System.out.println("in beforeClassMethod");<br />    }<br /><br />    <font color="#ff0000">@AfterClass</font><br />    protected void afterClassMethod() {<br />        System.out.println("in afterClassMethod");<br />    }<br /></td></tr></tbody></table><br />     不同于JUnit4，TestNG提供了以下的特性：<br />    <b> 依赖性测试<br />     </b>JUnit 框架想达到的一个目标就是测试隔离。它的缺点是：人们很难确定测试用例执行的顺序，而这对于任何类型的依赖性测试都非常重要。开发者们使用了多种技术来解决这个问题，例如，按字母顺序指定测试用例，或是更多地依靠 fixture 来适当地解决问题。<br />      与 JUnit 不同，TestNG 利用 <code>Test</code> 注释的 <code> dependsOnMethods </code> 属性来应对测试的依赖性问题。有了这个便利的特性，就可以轻松指定依赖方法。如以下定义：testMethod2依赖于testMethod1。<br />    <br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td>    @Test<br />    public void testMethod1() {<br />        System.out.println("in testMethod1");<br />    }<br /><br />   <font color="#ff0000"> @Test(dependsOnMethods="testMethod1")</font><br />    public void testMethod2() {<br />        System.out.println("in testMethod2");<br />    }<br /></td></tr></tbody></table>
当然如果testMethod1失败的话，默认testMethod2也不会执行，不过只需要设置alwaysRun = true，则可以跳过testMethod1<br /><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td>    @Test<br />
    public void testMethod1() {<br />
        System.out.println("in testMethod1");<br />        throw new RuntimeException("failed");<br />
    }<br /><br />
   <font color="#ff0000"> @Test(dependsOnMethods="testMethod1",alwaysRun = true)</font><br />
    public void testMethod2() {<br />
        System.out.println("in testMethod2");<br />
    }</td></tr></tbody></table><br />     <b>失败和重运行<br />     </b>在大型测试套件中，这种重新运行失败测试的能力显得尤为方便。这是 TestNG 独有的一个特性。在 JUnit 4 中，如果测试套件包括
1000 项测试，其中 3 项失败，很可能就会迫使您重新运行整个测试套件（修改错误以后）。不用说，这样的工作可能会耗费几个小时。

<p>一旦 TestNG 中出现失败，它就会创建一个 XML 配置文件，对失败的测试加以说明。如果利用这个文件执行 TestNG 运行程序，TestNG 就<i>只</i> 运行失败的测试。所以，在前面的例子里，您只需重新运行那三个失败的测试，而不是整个测试套件。可以看到以下的失败文件，一般命名为testng-failed.xml，以后只需要运行此文件就可以了。</p><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td>&lt;!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"&gt;<br />&lt;suite thread-count="5" verbose="1" name="Failed suite [testng]" parallel="false" annotations="JDK5"&gt;<br />  &lt;test name="demo.testng.Test2(failed)" junit="false" parallel="false" annotations="JDK5"&gt;<br />    &lt;classes&gt;<br />      &lt;class name="demo.testng.Test2"&gt;<br />        &lt;methods&gt;<br />          &lt;include name="testMethod1"/&gt;<br />          &lt;include name="testMethod2"/&gt;<br />          &lt;include name="beforeClassMethod"/&gt;<br />          &lt;include name="afterClassMethod"/&gt;<br />          &lt;include name="beforeMethod"/&gt;<br />          &lt;include name="afterMethod"/&gt;<br />        &lt;/methods&gt;<br />      &lt;/class&gt;<br />    &lt;/classes&gt;<br />  &lt;/test&gt;<br />&lt;/suite&gt;<br /></td></tr></tbody></table><br />   <b> 参数化测试<br />    </b>TestNG 中另一个有趣的特性是<i>参数化测试</i>。在 JUnit 中，如果您想改变某个受测方法的参数组，就只能给<i>每个</i> 不同的参数组编写一个测试用例。多数情况下，这不会带来太多麻烦。然而，我们有时会碰到一些情况，对其中的业务逻辑，需要运行的测试数目变化范围很大。<br />    在这样的情况下，使用 JUnit 的测试人员往往会转而使用 FIT 这样的框架，因为这样就可以用表格数据驱动测试。但是 TestNG
提供了开箱即用的类似特性。通过在 TestNG 的 XML
配置文件中放入参数化数据，就可以对不同的数据集重用同一个测试用例，甚至有可能会得到不同的结果。这种技术完美地避免了<i>只能</i> 假定一切正常的测试，或是没有对边界进行有效验证的情况。<br /><br /><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td>   <font color="#ff0000">@Parameters( { "first-name"<br />    })</font><br />    @Test(groups = { "param"<br />    })<br />    public void testParm(String firstName) {<br />        System.out.println("invoked testString:" + firstName);<br />        assertEquals(firstName, "Test");<br />    }<br /></td></tr></tbody></table><br />在xml中设置相应的参数值，可以放入suite下面或者test下面，如果同名，一般test下面的定义覆盖suite定义。<br /><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td><font color="#ff0000">&lt;parameter name="first-name" value="Test"/&gt;</font><br /></td></tr></tbody></table><br /><b>    高级参数化测试<br /></b>    尽管从一个 XML 文件中抽取数据会很方便，但偶尔会有些测试需要有复杂类型，这些类型无法用 <code>String</code> 或原语值来表示。TestNG 可以通过它的 <code>@DataProvider</code> 注释处理这样的情况。<code>@DataProvider</code> 注释可以方便地把复杂参数类型映射到某个测试方法。例如，清单 7 中的 <code> verifyHierarchy </code> 测试中，我采用了重载的 <code>buildHierarchy</code> 方法，它可接收一个 <code>Class</code> 类型的数据, 它断言（asserting）<code>Hierarchy</code> 的 <code> getHierarchyClassNames()</code> 方法应该返回一个适当的字符串数组：<br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" height="47" width="676"><tbody><tr><td><pre class="section">package test.com.acme.da.ng;<br /><br />import java.util.Vector;<br /><br />import static org.testng.Assert.assertEquals;<br />import org.testng.annotations.DataProvider;<br />import org.testng.annotations.Test;<br /><br />import com.acme.da.hierarchy.Hierarchy;<br />import com.acme.da.hierarchy.HierarchyBuilder;<br /><br />public class HierarchyTest {<br /><br /><font color="#ff0000">@DataProvider(name = "class-hierarchies")</font><br /> public Object[][] dataValues(){<br />  return new Object[][]{<br />   {Vector.class, new String[] {"java.util.AbstractList", <br />     "java.util.AbstractCollection"}},<br />   {String.class, new String[] {}}<br />  };<br /> }<br /><br /><font color="#ff0000">@Test(dataProvider = "class-hierarchies")</font><br /> public void verifyHierarchy(Class clzz, String[] names) <br />  throws Exception{<br />    Hierarchy hier = HierarchyBuilder.buildHierarchy(clzz);<br />    assertEquals(hier.getHierarchyClassNames(), names, <br />	  "values were not equal");		<br /> }<br />}</pre></td></tr></tbody></table><br />     当然还有一些其他的特性，就不一一详细说明了，有兴趣可以参考相应的testNG文档。<br />      JUnit 4 和 TestNG 在表面上是相似的。然而，设计 JUnit 的目的是为了分析代码单元，而 TestNG
的预期用途则针对高级测试。对于大型测试套件，我们不希望在某一项测试失败时就得重新运行数千项测试，TestNG
的灵活性在这里尤为有用。这两个框架都有自己的优势，您可以随意同时使用它们。

<img src ="http://www.blogjava.net/zyl/aggbug/73468.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zyl/" target="_blank">布衣郎</a> 2006-10-05 15:44 <a href="http://www.blogjava.net/zyl/archive/2006/10/05/73468.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Junit 4新的特性</title><link>http://www.blogjava.net/zyl/archive/2006/10/03/73255.html</link><dc:creator>布衣郎</dc:creator><author>布衣郎</author><pubDate>Tue, 03 Oct 2006 02:36:00 GMT</pubDate><guid>http://www.blogjava.net/zyl/archive/2006/10/03/73255.html</guid><wfw:comment>http://www.blogjava.net/zyl/comments/73255.html</wfw:comment><comments>http://www.blogjava.net/zyl/archive/2006/10/03/73255.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/zyl/comments/commentRss/73255.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zyl/services/trackbacks/73255.html</trackback:ping><description><![CDATA[    JUnit 4
已经出来很久了，基本上很多ide都开始支持，当然为了兼容性，一直不太敢用。以前都是懒得写单元测试，大多数的时候都是
System.out.print。不过现在已经是测试驱动的时代了，为了保持一个良好的习惯，还是需要好好的写写单元测试。断言远比
System.out.print有用。<br />
    看了几篇文章之后，对JUnit4已经有了基本的概念了。其实很多特性，testNg都已经实现了，挺讨厌testNg的xml文件，不过testNg的灵活性还是强大，对于大面积的组件测试比较适合。<br />
    JUnit 4应该说是使用新的架构写的，使用了很多java5的新特性。<br />
    一个最关键的改变，测试类，可以不用继承那该死的<span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">TestCase了.测试类，可以更加灵活，方法的定义不需要在前面增加test了。<br />
    对于测试类来说，只需要做以下简单的动作：<br />
    增加一个@Test，用于标注相应的测试方法。使用Assert类，来进行断言。<br />
    </span><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" height="286" width="608"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">import org.junit.Assert;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">public class AdditionTest {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>private int x =
  1;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>private int y =
  1;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span><font color="#ff0000">@Test </font>public
  void addition() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>int z = x +
  y;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">   
  </span>Assert.assertEquals(2, z);<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>}<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p></span></p></td></tr></tbody></table><br />
当然可以使用java 5的static import 功能<br /><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" height="292" width="609"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><font color="#ff3300">import static org.junit.Assert.*;</font><o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">public class AdditionTest {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>private int x =
  1;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>private int y =
  1;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span><font color="#ff3300">@</font><font color="#ff3300">Test </font>public
  void addition() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>int z = x +
  y;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">   
  </span>assertEquals(2, z);<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>}<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p></span></p></td></tr></tbody></table><br />
对于setUp 和tearDown来说，以后可以不用再继承这两个方法了。可以使用自定义的方法，只需要在前面增加@Before 和@After 注释即可。<br /><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" height="208" width="610"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">@<font color="#ff0000">Before </font>protected void initialize() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">   
  </span>System.setErr(new PrintStream(new ByteArrayOutputStream()));<o:p></o:p><span style="">    </span><o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>inputDir =
  new File("data");<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>inputDir =
  new File(inputDir, "xslt");<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>inputDir =
  new File(inputDir, "input");<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">        </span><o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p></span></p></td></tr></tbody></table><br /><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" height="168" width="611"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><font color="#ff3300">@After</font> protected void disposeDocument() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>doc = null;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style=""> 
  </span>System.gc();<span style="">   </span><o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">} <o:p></o:p></span></p></td></tr></tbody></table><br />
并且可以注释多个方法。<br /><br />
    当然JUnit4 <span style="font-size: 12pt; font-family: 宋体;">也引入了一个<span lang="EN-US"> JUnit 3 </span>中没有的新特性：类范围的 <span lang="EN-US">setUp() </span>和 <span lang="EN-US">tearDown() </span>方法。任何用 <span lang="EN-US">@BeforeClass </span>注释的方法都将在该类中的测试方法运行之前刚好运行一次，而任何用 <span lang="EN-US">@AfterClass </span>注释的方法都将在该类中的所有测试都运行之后刚好运行一次。<br />
    </span><span style="font-size: 12pt; font-family: 宋体;">例 如，假设类中的每个测试都使用一个数据库连接、一个网络连接、一个非常大的数据结构，或者还有一些对于初始化和事情安排来说比较昂贵的其他资源。不要在每
个测试之前都重新创建它，您可以创建它一次，并还原它一次。该方法将使得有些测试案例运行起来快得多。<br /><br /></span><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" height="418" width="606"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">// This class tests a lot of error conditions, which<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">// Xalan annoyingly logs to System.err. This hides
  System.err <o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">// before each test and restores it after each test.<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">private PrintStream systemErr;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><font color="#ff3300">@BeforeClass</font> protected void redirectStderr() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>systemErr =
  System.err; // Hold on to the original value<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">   
  </span>System.setErr(new PrintStream(new ByteArrayOutputStream()));<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p><span style=""> </span><o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><font color="#ff0000">@AfterClass </font>protected void tearDown() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>// restore
  the original value<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">   
  </span>System.setErr(systemErr);<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p></span></p></td></tr></tbody></table><br /><span style="font-size: 12pt; font-family: 宋体;">    异常测试是<span lang="EN-US"> JUnit 4 </span>中的最大改进。旧式的异常测试是在抛出异常的代码中放入
<span lang="EN-US">try </span>块，然后在 <span lang="EN-US">try </span>块的末尾加入一个 <span lang="EN-US">fail() </span>语句。<br /></span><span style="font-size: 12pt; font-family: 宋体;">该方法不仅难看，而且试图挑战代码覆盖工具，因为不管测试是通过还是失败，总有一些代码不被执行。</span><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US"> JUnit 4 </span>中，您现在可以编写抛出异常的代码，并使用注释来声明该异常是预期的：
<br /></span><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" height="168" width="607"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><font color="#ff0000">@Test(expected=ArithmeticException.class)</font><o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>public void
  divideByZero() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">    </span>int n = 2 /
  0;<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p></span></p></td></tr></tbody></table><br /><span style="font-size: 12pt; font-family: 宋体;">    如果该异常没有抛出（或者抛出了一个不同的异常），那么测试就将失败。但是如果您想要测试异常的详细消息或其他属性，则仍然需要使用旧式的
<span lang="EN-US">try-catch </span>样式。<br /></span><a name="N101BE"><span style="font-size: 12pt; font-family: 宋体;">    测试性能 是单元测试最为痛苦的方面之一。<span lang="EN-US">JUnit 4 </span>没有完全解决这个问题，但是它对这个问题有所帮助。测试可以用一个超时参数来注释。如果测试运行的时间超过指定的毫秒数，则测试失败。</span></a><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span><br /><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" height="134" width="613"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">@Test(timeout=500) public void
  retrieveAllElementsInDocument() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">   
  </span>doc.query("//*");<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">} <o:p></o:p></span></p></td></tr></tbody></table><br />
基本的特性就这么多，这些功能其实都可以在testNg中找到。不过JUnit还是不错的，对于单元测试来说，这是首选的。<br /><br />
当然为了兼容性，<span style="font-size: 12pt; font-family: 宋体;">为了使<span lang="EN-US"> JUnit 4 </span>测试可以运行在<span lang="EN-US"> JUnit 3 </span>环境中，可以将它们包装在
<span lang="EN-US">JUnit4TestAdapter </span>中。将下面的方法添加到您的<span lang="EN-US"> JUnit
4 </span>测试类中应该就足够了： <span lang="EN-US"><o:p></o:p></span></span><br /><br /><table class="MsoNormalTable" style="background: rgb(238, 238, 238) none repeat scroll 0% 50%; width: 100%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" border="1" cellpadding="0" cellspacing="0" width="100%"><tbody><tr style=""><td style="padding: 3.75pt;"><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">public static junit.framework.Test suite() {<o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">  </span>return new
  JUnit4TestAdapter(AssertionTest.class);<span style="">   
  </span><o:p></o:p></span></p><p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p></span></p></td></tr></tbody></table><br /><br /><img src ="http://www.blogjava.net/zyl/aggbug/73255.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zyl/" target="_blank">布衣郎</a> 2006-10-03 10:36 <a href="http://www.blogjava.net/zyl/archive/2006/10/03/73255.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EasyMock 2 使用指南</title><link>http://www.blogjava.net/zyl/archive/2006/09/20/70897.html</link><dc:creator>布衣郎</dc:creator><author>布衣郎</author><pubDate>Wed, 20 Sep 2006 12:38:00 GMT</pubDate><guid>http://www.blogjava.net/zyl/archive/2006/09/20/70897.html</guid><wfw:comment>http://www.blogjava.net/zyl/comments/70897.html</wfw:comment><comments>http://www.blogjava.net/zyl/archive/2006/09/20/70897.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/zyl/comments/commentRss/70897.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zyl/services/trackbacks/70897.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="" lang="EN-US">关于单元测试，模拟对象一直是不可缺少的，尤其对于复杂的应用来说。<br />       这么多的模拟对象框架中，个人觉得比较好用的当属EasyMock了。当然JMock也不错。<br />       下面简单介绍一下EasyMock 。（基本翻译EasyMock的文档，可能有些地方不是很恰当）<br />      <br />       EasyMock 2</span>
				<span style="font-family: 宋体;">主要用于给指定的接口提供模拟对象。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">模拟对象只是模拟领域代码直接的部分行为，能检测是否他们如定义中的被使用。使用</span>
				<span style="" lang="EN-US">Mock </span>
				<span style="font-family: 宋体;">对象，来模拟合作接口，有助于隔离测试相应的领域类。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">创建和维持</span>
				<span style="" lang="EN-US">Mock </span>
				<span style="font-family: 宋体;">对象经常是繁琐的任务，并且可能会引入错误。</span>
				<span style="" lang="EN-US">EasyMock 2 </span>
				<span style="font-family: 宋体;">动态产生</span>
				<span style="" lang="EN-US">Mock </span>
				<span style="font-family: 宋体;">对象，不需要创建，并且不会产生代码。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">有利的方面：</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">不需要手工写类来处理</span>
				<span style="" lang="EN-US">mock </span>
				<span style="font-family: 宋体;">对象。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">支持安全的重构</span>
				<span style="" lang="EN-US">Mock</span>
				<span style="font-family: 宋体;">对象：测试代码不会在运行期打断当重新命名方法或者更改方法参数。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">支持返回值和例外。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">支持检察方法调用次序，对于一个或者多个</span>
				<span style="" lang="EN-US">Mock </span>
				<span style="font-family: 宋体;">对象。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;">
				<span style="font-family: 宋体;">不利的方面：</span>
				<font size="4">
						<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">2.0</span>
						<span style="font-size: 10.5pt; font-family: 宋体;">仅使用于</span>
						<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">java 2</span>
						<span style="font-size: 10.5pt; font-family: 宋体;">版本</span>
						<span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">5.0</span>
				</font>
				<span style="font-size: 10.5pt; font-family: 宋体;">
						<font size="4">或者以上</font>
						<br />    <br /><br />    <font size="4">以一个例子来说明如何使用EasyMock:<br />   假设有一个合作接口<span style="font-size: 10.5pt; color: black;" lang="EN-US">Collaborator：<br />    <font size="3">        </font></span></font><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US">package org.easymock.samples;<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p> </o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US">public interface Collaborator {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>void documentAdded(String title);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>void documentChanged(String title);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>void documentRemoved(String title);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>byte voteForRemoval(String title);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>byte[] voteForRemovals(String[] title);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US">}<font size="4"><font style="background-color: rgb(204, 204, 204);"><font face="Lucida Console"><code class="section"><o:p></o:p></code></font></font></font></span></pre></pre></td></tr></tbody></table></span>
		</p>我们主要的测试类为：<br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"></span><span style="font-size: 10.5pt;" lang="EN-US">package org.easymock.samples;<o:p></o:p></span><br />import java.util.HashMap;<br />import java.util.HashSet;<br />import java.util.Map;<br />import java.util.Set;</pre><pre>public class ClassUnderTest {</pre><pre>    private Set&lt;Collaborator&gt; listeners = new HashSet&lt;Collaborator&gt;();</pre><pre>    private Map&lt;String, byte[]&gt; documents = new HashMap&lt;String, byte[]&gt;();</pre><pre>    public void addListener(Collaborator listener) {<br />        listeners.add(listener);<br />    }</pre><pre>    public void addDocument(String title, byte[] document) {<br />        boolean documentChange = documents.containsKey(title);<br />        documents.put(title, document);<br />        if (documentChange) {<br />            notifyListenersDocumentChanged(title);<br />        } else {<br />            notifyListenersDocumentAdded(title);<br />        }<br />    }</pre><pre>    public boolean removeDocument(String title) {<br />        if (!documents.containsKey(title)) {<br />            return true;<br />        }</pre><pre>        if (!listenersAllowRemoval(title)) {<br />            return false;<br />        }</pre><pre>        documents.remove(title);<br />        notifyListenersDocumentRemoved(title);</pre><pre>        return true;<br />    }</pre><pre>    public boolean removeDocuments(String[] titles) {<br />        if (!listenersAllowRemovals(titles)) {<br />            return false;<br />        }</pre><pre>        for (String title : titles) {<br />            documents.remove(title);<br />            notifyListenersDocumentRemoved(title);<br />        }<br />        return true;<br />    }</pre><pre>    private void notifyListenersDocumentAdded(String title) {<br />        for (Collaborator listener : listeners) {<br />            listener.documentAdded(title);<br />        }<br />    }</pre><pre>    private void notifyListenersDocumentChanged(String title) {<br />        for (Collaborator listener : listeners) {<br />            listener.documentChanged(title);<br />        }<br />    }</pre><pre>    private void notifyListenersDocumentRemoved(String title) {<br />        for (Collaborator listener : listeners) {<br />            listener.documentRemoved(title);<br />        }<br />    }</pre><pre>    private boolean listenersAllowRemoval(String title) {<br />        int result = 0;<br />        for (Collaborator listener : listeners) {<br />            result += listener.voteForRemoval(title);<br />        }<br />        return result &gt; 0;<br />    }</pre><pre>    private boolean listenersAllowRemovals(String[] titles) {<br />        int result = 0;<br />        for (Collaborator listener : listeners) {<br />            result += listener.voteForRemovals(titles);<br />        }<br />        return result &gt; 0;<br />    }</pre><pre>}</pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: 宋体;">第一个</span><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" lang="EN-US">Mock </span><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: 宋体;">对象</span><span style="" lang="EN-US"><o:p></o:p></span></p><span style="font-size: 10.5pt; font-family: 宋体;">我们将创建</span><span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">test case </span><span style="font-size: 10.5pt; font-family: 宋体;">并且围绕此理解相关的</span><span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">EasyMock </span><span style="font-size: 10.5pt; font-family: 宋体;">包的功能。第一个测试方法，用于检测是否删除一个不存在的文档，不会发通知给合作类。<br />    <font size="3">      </font><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p><pre><span style="font-size: 10.5pt;" lang="EN-US">package org.easymock.samples;<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p> </o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US">import junit.framework.TestCase;<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p> </o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US">public class ExampleTest extends TestCase {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p> </o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>private ClassUnderTest classUnderTest;<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>private Collaborator mock;<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p> </o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>protected void setUp() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest = new ClassUnderTest();<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addListener(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p> </o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>public void testRemoveNonExistingDocument() {<span style="">    </span><o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>// This call should not lead to any notification<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">     </span><span style="">   </span>// of the Mock Object: <o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.removeDocument("Does not exist");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US">}<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></span></pre></pre></td></tr></tbody></table></span><font face="宋体">    <span style="font-size: 10.5pt; font-family: 宋体;">对于多数测试类，使用</span><span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">EasyMock 2,</span><span style="font-size: 10.5pt; font-family: 宋体;">我们只需要静态引入</span></font><font face="宋体"><code><span style="font-size: 10.5pt; color: black;" lang="EN-US">org.easymock.EasyMock</span></code><code><span style="font-size: 10.5pt; color: black;">的方法。</span></code>       </font><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: red; font-family: 'Courier New';" lang="EN-US">import static org.easymock.EasyMock.*;<o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US">import junit.framework.TestCase;<o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US">public class ExampleTest extends TestCase {<o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US"><span style="">    </span>private ClassUnderTest classUnderTest;<o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US"><span style="">    </span>private Collaborator mock;<o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US"><span style="">    </span><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; background: rgb(204, 204, 204) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; text-align: left;" align="left"><span style="color: black; font-family: 'Courier New';" lang="EN-US">}<o:p></o:p></span></p></pre></pre></td></tr></tbody></table><font face="宋体">      
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-family: 宋体;">为了取得</span><span style="" lang="EN-US"><font face="Times New Roman">Mock </font></span><span style="font-family: 宋体;">对象，需要：</span><span style="" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt 45pt; text-indent: -21pt;"><span style="font-family: Wingdings;" lang="EN-US"><span style="">l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">         </span></span></span><span style="font-family: 宋体;">创建</span><span style="" lang="EN-US"><font face="Times New Roman">Mock </font></span><span style="font-family: 宋体;">对象从需要模拟的接口</span><span style="" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt 45pt; text-indent: -21pt;"><span style="font-family: Wingdings;" lang="EN-US"><span style="">l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">         </span></span></span><span style="font-family: 宋体;">记录期待的行为</span><span style="" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt 45pt; text-indent: -21pt;"><span style="font-family: Wingdings;" lang="EN-US"><span style="">l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">         </span></span></span><span style="font-family: 宋体;">转换到</span><span style="" lang="EN-US"><font face="Times New Roman">Mock</font></span><span style="font-family: 宋体;">对象，</span><span style="" lang="EN-US"><font face="Times New Roman">replay</font></span><span style="font-family: 宋体;">状态。</span><span style="" lang="EN-US"><o:p></o:p></span></p><span style="font-size: 10.5pt; font-family: 宋体;">例如：</span>      </font><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">protected void setUp() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span></span><span style="font-size: 10.5pt; color: red;" lang="EN-US"><span style="">    </span>mock = createMock(Collaborator.class); // 1<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest = new ClassUnderTest();<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addListener(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<br /><br /><o:p></o:p><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style=""> </span>public void testRemoveNonExistingDocument() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>// 2 (we do not expect anything)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span></span><span style="font-size: 10.5pt; color: red;" lang="EN-US">replay(mock); // 3<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.removeDocument("Does not exist");<o:p></o:p></span></pre><span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US"><span style="">    </span>}</span></span></pre></pre></pre></td></tr></tbody></table><font face="宋体">   
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-family: 宋体;">在执行第三步后，</span><span style="" lang="EN-US"><font face="Times New Roman">mock </font></span><span style="font-family: 宋体;">为</span><code><span style="color: black;" lang="EN-US"><font face="宋体">Collaborator</font></span></code><span style="color: black; font-family: Arial;" lang="EN-US"></span><span style="color: black; font-family: 宋体;">接口的</span><span style="" lang="EN-US"><font face="Times New Roman">Mock</font></span><span style="font-family: 宋体;">对象，并且期待没有什么调用。这就意味着，如果我们改变</span><span style="" lang="EN-US"><font face="Times New Roman">ClassUnderTest</font></span><span style="font-family: 宋体;">去调用此接口的任何方法，则</span><span style="" lang="EN-US"><font face="Times New Roman">Mock</font></span><span style="font-family: 宋体;">对象会抛出</span><span style="" lang="EN-US"><font face="Times New Roman">AssertionError</font></span><span style="font-family: 宋体;">：</span><span style="" lang="EN-US"><o:p></o:p></span></p>         </font><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">java.lang.AssertionError: <o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">  </span>Unexpected method call documentRemoved("Does not exist"):<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at $Proxy0.documentRemoved(Unknown Source)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>...<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: 宋体;">增加行为</span><span style="" lang="EN-US"><o:p></o:p></span></p>       <span style="font-family: 宋体;">让我们开始第二个测试。如果</span><span style="" lang="EN-US">document</span><span style="font-family: 宋体;">被</span><span style="" lang="EN-US">classUnderTest</span><span style="font-family: 宋体;">增加，我们期待调用</span><span style="" lang="EN-US"><br /></span><font face="宋体"><code><span style="color: black;" lang="EN-US">mock.documentAdded()</span></code><code><span style="color: black;">在<span lang="EN-US">Mock</span>对象使用<span lang="EN-US">document</span>的标题作为参数：<span lang="EN-US"><o:p></o:p></span></span></code></font><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US"><span style=""> </span>public void testAddDocument() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">       </span></span><span style="font-size: 10.5pt; color: red;" lang="EN-US"><span style=""> </span>mock.documentAdded("New Document");</span><span style="font-size: 10.5pt;" lang="EN-US"> // 2<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>replay(mock); // 3<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("New Document", new byte[0]); <o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><span style="font-size: 10.5pt; font-family: 宋体;">如果</span><font face="宋体"><code><span style="font-size: 10.5pt; color: black;" lang="EN-US">classUnderTest.addDocument("New Document", new byte[0])</span></code><code><span style="font-size: 10.5pt; color: black;">调用期待的方法，使用错误的参数，<span lang="EN-US">Mock</span>对象会抛出<span lang="EN-US">AssertionError:</span></span></code></font><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">java.lang.AssertionError: <o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">  </span>Unexpected method call documentAdded("Wrong title"):<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>documentAdded("New Document"): expected: 1, actual: 0<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at $Proxy0.documentAdded(Unknown Source)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>...<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-family: 宋体;">同样，如果调用多次此方法，则也会抛出例外：</span><br /></p><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">java.lang.AssertionError: <o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">  </span>Unexpected method call documentAdded("New Document"):<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>documentAdded("New Document"): expected: 1, actual: 1 (+1)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at $Proxy0.documentAdded(Unknown Source)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>...<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: 宋体;">验证行为</span><span style="" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><span style="">       </span></span><span style="font-family: 宋体;">当我们指定行为后，我们将验证实际发生的。当前的测试将会判断是否</span><span style="" lang="EN-US">Mock</span><span style="font-family: 宋体;">对象会真实调用。可以调用</span><font face="宋体"><code><span style="color: black;" lang="EN-US">verify(mock)</span></code><code><span style="color: black;">来山正是否指定的行为被调用。</span></code></font><br /></p><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">public void testAddDocument() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentAdded("New Document"); // 2 <o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>replay(mock); // 3<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("New Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">       </span></span><span style="font-size: 10.5pt; color: red;" lang="EN-US"><span style=""> </span>verify(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-family: 宋体;">如果失败，则抛出</span><span style="" lang="EN-US">AssertionError<o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: 宋体;">期待明显数量的调用</span><span style="" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 10.5pt; font-family: 宋体;">到现在，我们的测试只是调用一个简单的方法。下一个测试将会检测是否已经存在</span><span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">document</span><span style="font-size: 10.5pt; font-family: 宋体;">导致</span><font face="宋体"><code><span style="font-size: 10.5pt; color: black;" lang="EN-US">mock.documentChanged()</span></code><code><span style="font-size: 10.5pt; color: black;">调用。为了确认，调用三次</span></code></font></p><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">public void testAddAndChangeDocument() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentAdded("Document");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentChanged("Document");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentChanged("Document");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentChanged("Document");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>replay(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>verify(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-family: 宋体;">为了避免重复的</span><code><span style="color: black;" lang="EN-US"><font face="宋体">mock.documentChanged("Document")</font></span></code><span style="color: black; font-family: Arial;" lang="EN-US">,EasyMock</span><span style="color: black; font-family: 宋体;">提供一个快捷方式。可以通过调用方法</span><font face="宋体"><code><span style="color: black;" lang="EN-US">expectLastCall().times(int times)</span></code><code><span style="color: black;">来指定最后一次调用的次数。</span></code></font><br /></p><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US"><span style=""> </span>public void testAddAndChangeDocument() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentAdded("Document");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentChanged("Document");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span></span><span style="font-size: 10.5pt; color: red;" lang="EN-US">expectLastCall().times(3);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>replay(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>verify(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><br /><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: 宋体;">指定返回值</span><span style="" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="" lang="EN-US"><span style="">       </span></span><span style="font-family: 宋体;">对于指定返回值，我们通过封装</span><font face="宋体"><code><span style="color: black;" lang="EN-US">expect(T value)</span></code><code><span style="color: black;">返回的对象并且指定返回的值，使用方法<span lang="EN-US">andReturn(Object returnValue)</span>于<span lang="EN-US">expect(T value)</span></span></code></font><span style="color: black; font-family: Arial;" lang="EN-US">.</span><span style="color: black; font-family: 宋体;">返回的对象。</span><span style="color: black; font-family: Arial;" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="color: black; font-family: 宋体;">例如：</span><span style="color: black; font-family: Arial;" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"></p><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">public void testVoteForRemoval() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentAdded("Document");<span style="">   </span>// expect document addition<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>// expect to be asked to vote for document removal, and vote for it<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span></span><span style="font-size: 10.5pt; color: red;" lang="EN-US">expect(mock.voteForRemoval("Document")).andReturn((byte) 42);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentRemoved("Document"); // expect document removal<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>replay(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre style="margin-left: 42pt; text-indent: -42pt;"><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>assertTrue(classUnderTest.removeDocument("Document"));<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>verify(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>} <o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p> </o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>public void testVoteAgainstRemoval() {<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>mock.documentAdded("Document");<span style="">   </span>// expect document addition<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>// expect to be asked to vote for document removal, and vote against it<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span></span><span style="font-size: 10.5pt; color: red;" lang="EN-US">expect(mock.voteForRemoval("Document")).andReturn((byte) -42);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>replay(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>classUnderTest.addDocument("Document", new byte[0]);<o:p></o:p></span></pre><pre style="margin-left: 42pt; text-indent: -42pt;"><span style="font-size: 10.5pt;" lang="EN-US"><span style="">        </span>assertFalse(classUnderTest.removeDocument("Document"));<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">  </span><span style="">      </span>verify(mock);<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><span style="">    </span>}<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><span style="font-size: 10.5pt; font-family: 宋体;">取代</span><font face="宋体"><code><span style="font-size: 10.5pt; color: black;" lang="EN-US">expect(T value)</span></code><code><span style="font-size: 10.5pt; color: black;">调用，可以通过<span lang="EN-US">expectLastCall()</span></span></code></font><span style="font-size: 10.5pt; color: black; font-family: Arial;" lang="EN-US">.</span><span style="font-size: 10.5pt; color: black; font-family: 宋体;">来代替</span><br /><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <span style="font-size: 10.5pt; font-family: 'Times New Roman';" lang="EN-US">expect(mock.voteForRemoval("Document")).andReturn((byte) 42);</span></pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-family: 宋体;">等同于</span><br /></p><table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%"><tbody><tr><td><pre><pre><span style="font-size: 10.5pt;" lang="EN-US"><o:p></o:p></span> <pre><span style="font-size: 10.5pt;" lang="EN-US">mock.voteForRemoval("Document");<o:p></o:p></span></pre><pre><span style="font-size: 10.5pt;" lang="EN-US">expectLastCall().andReturn((byte) 42);<font style="background-color: rgb(204, 204, 204);"><o:p></o:p></font></span></pre></pre></pre></td></tr></tbody></table><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="background: lime none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: 宋体;">处理例外</span><span style="" lang="EN-US"><o:p></o:p></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-family: 宋体;">对于指定的例外</span><span style="" lang="EN-US">(</span><span style="font-family: 宋体;">更确切的</span><span style="" lang="EN-US">:Throwables)</span><span style="font-family: 宋体;">被抛出，由</span><font face="宋体"><code><span style="font-size: 12pt; color: black;" lang="EN-US">expectLastCall()</span></code><code><span style="font-size: 12pt; color: black;">和<span lang="EN-US">expect(T value)</span></span></code><span style="font-family: 宋体;">返回的对象，提供了方法</span><code><span style="font-size: 12pt; color: black;" lang="EN-US">andThrow(Throwable throwable)</span></code><code><span style="font-size: 12pt; color: black;">。方法不得不被调用记录状态，在调用<span lang="EN-US">Mock</span>对象后，对于此指定了要抛出的<span lang="EN-US">Throwable</span>。<span lang="EN-US"><o:p></o:p></span></span></code></font></p><br />基本的方法，已经说完了，当然这不能完全说明EasyMock的使用。更多的因素请参考EasyMock的文档<br /><a href="http://www.easymock.org/Documentation.html">http://www.easymock.org/Documentation.html</a><br /><img src ="http://www.blogjava.net/zyl/aggbug/70897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zyl/" target="_blank">布衣郎</a> 2006-09-20 20:38 <a href="http://www.blogjava.net/zyl/archive/2006/09/20/70897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>