??xml version="1.0" encoding="utf-8" standalone="yes"?>国产视频亚洲精品,亚洲精品一区二区三区中文字幕,992tv在线观看免费进http://www.aygfsteel.com/zyl/category/17750.html好好学习Q天天向?/description>zh-cnTue, 27 Feb 2007 20:02:06 GMTTue, 27 Feb 2007 20:02:06 GMT60关于TestNGhttp://www.aygfsteel.com/zyl/archive/2006/10/05/73468.html布衣?/dc:creator>布衣?/author>Thu, 05 Oct 2006 07:44:00 GMThttp://www.aygfsteel.com/zyl/archive/2006/10/05/73468.htmlhttp://www.aygfsteel.com/zyl/comments/73468.htmlhttp://www.aygfsteel.com/zyl/archive/2006/10/05/73468.html#Feedback2http://www.aygfsteel.com/zyl/comments/commentRss/73468.htmlhttp://www.aygfsteel.com/zyl/services/trackbacks/73468.html       TestNG是一个不错的试框架Q尤其是用于模块试Q以及大范围的测试。相对于JUnit来说Q更为灵zR随着JUnit4的推出,很多功能都与TestNG怼Q但相对于JUnit4QTestNGq是有很多部分是有区别的?br />      TestNG的IDE支持也不错,对于Eclipse,Idea,Ant都有很好的支持?br />      先来看一看怎么使用TestNGQ当焉先需要下载TestNG包。目前的版本?.1Q下载地址如下Q?br />      http://testng.org/doc/download.html Q也可以下蝲相应的Eclipse插g?br />      q行TestNGQ可以从命o行或者IDEQ或者Ant中运行?br />      命o行:
      java org.testng.TestNG -groups windows,linux -testclass org.test.MyTest
     
对于大型的测试,需要定义一个xml文gQ一般ؓtestng.xml?br />   


<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
 
<suitename="Suite1"   verbose="1" >
<testname="Nopackage" >
<classes>
       <classname="NoPackageTest"  />
</classes>
</test>

<testname="Regression1"   >
<classes>
<classname="test.sample.ParameterSample"  />
<classname="test.sample.ParameterTest" />
</classes>
</test>
</suite>

     java org.testng.TestNG testng.xml
   
  当然如果使用Eclipse插gQ就单多了?b>

      下面来看一下,如何来实现测试的Q与JUnit4 差不多(怀疑,JUnit4是不是有抄袭TestNG的成分)?br />      声明试Ҏ如下Q?span style="font-size: 10.5pt; font-family: "Times New Roman";" lang="EN-US">


  @Test
public void testMethod1() {
System.out.println("in testMethod1");
}

@Test
public void testMethod2() {
System.out.println("in testMethod2");
}

     基本上都是采用java5的注释实现的?br />     与JUnit4 不同在于Q测试方法可以分l,它可以根据诸如运行时间这L特征来对试分类?br />
  @Test(groups={"fun1","fun2"})
public void testMethod1() {
System.out.println("in testMethod1");
}

@Test(groups={"fun1"})
public void testMethod2() {
System.out.println("in testMethod2");
}

      同JUnit4 一P同样支持Before,AfterҎQ如同setUp 和tearDown,不过TestNG更ؓ灉|Q支持各U签名方式,如private,protected?br />
    @BeforeMethod
    protected void beforeMethod() {
        System.out.println("in beforeMethod");
    }

    @AfterMethod
    protected void afterMethod() {
        System.out.println("in afterMethod");
    }

     同样也支持BeforeClass 和AfterClassQ只执行一ơ的ҎQ但是可以不需要用static{֐
    @BeforeClass
    protected void beforeClassMethod() {
        System.out.println("in beforeClassMethod");
    }

    @AfterClass
    protected void afterClassMethod() {
        System.out.println("in afterClassMethod");
    }

     不同于JUnit4QTestNG提供了以下的Ҏ:
     依赖性测?br />     JUnit 框架惌到的一个目标就是测试隔R它的缺ҎQh们很隄定测试用例执行的序Q而这对于Mcd的依赖性测试都非常重要。开发者们使用了多U技术来解决q个问题Q例如,按字母顺序指定测试用例,或是更多C?fixture 来适当地解决问题?br />      ?JUnit 不同QTestNG 利用 Test 注释? dependsOnMethods 属性来应对试的依赖性问题。有了这个便利的Ҏ,可以轻松指定依赖方法。如以下定义QtestMethod2依赖于testMethod1?br />   
    @Test
    public void testMethod1() {
        System.out.println("in testMethod1");
    }

    @Test(dependsOnMethods="testMethod1")
    public void testMethod2() {
        System.out.println("in testMethod2");
    }
当然如果testMethod1p|的话Q默认testMethod2也不会执行,不过只需要设|alwaysRun = trueQ则可以跌testMethod1

    @Test
    public void testMethod1() {
        System.out.println("in testMethod1");
        throw new RuntimeException("failed");
    }

    @Test(dependsOnMethods="testMethod1",alwaysRun = true)
    public void testMethod2() {
        System.out.println("in testMethod2");
    }

     p|和重q行
    
在大型测试套件中Q这U重新运行失败测试的能力昑־ؓ方便。这?TestNG 独有的一个特性。在 JUnit 4 中,如果试套g包括 1000 Ҏ试,其中 3 失败,很可能就会迫使您重新q行整个试套gQ修攚w误以后)。不用说Q这L工作可能会耗费几个时?

一?TestNG 中出现失败,它就会创Z?XML 配置文gQ对p|的测试加以说明。如果利用这个文件执?TestNG q行E序QTestNG ?i>?/i> q行p|的测试。所以,在前面的例子里,您只需重新q行那三个失败的试Q而不是整个测试套件。可以看C下的p|文gQ一般命名ؓtestng-failed.xmlQ以后只需要运行此文g可以了?/p>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite thread-count="5" verbose="1" name="Failed suite [testng]" parallel="false" annotations="JDK5">
  <test name="demo.testng.Test2(failed)" junit="false" parallel="false" annotations="JDK5">
    <classes>
      <class name="demo.testng.Test2">
        <methods>
          <include name="testMethod1"/>
          <include name="testMethod2"/>
          <include name="beforeClassMethod"/>
          <include name="afterClassMethod"/>
          <include name="beforeMethod"/>
          <include name="afterMethod"/>
        </methods>
      </class>
    </classes>
  </test>
</suite>

    参数化测?br />    TestNG 中另一个有的Ҏ是参数化测?/i>。在 JUnit 中,如果您想改变某个受测Ҏ的参数组Q就只能l?i>每个 不同的参数组~写一个测试用例。多数情况下Q这不会带来太多ȝ。然而,我们有时会碰C些情况,对其中的业务逻辑Q需要运行的试数目变化范围很大?br />    在这L情况下,使用 JUnit 的测试h员往往会{而?FIT q样的框Ӟ因ؓq样可以用表格数据驱动试。但?TestNG 提供了开即用的cMҎ。通过?TestNG ?XML 配置文g中放入参数化数据Q就可以对不同的数据集重用同一个测试用例,甚至有可能会得到不同的结果。这U技术完地避免?i>只能 假定一切正常的试Q或是没有对边界q行有效验证的情c?br />

   @Parameters( { "first-name"
    })

    @Test(groups = { "param"
    })
    public void testParm(String firstName) {
        System.out.println("invoked testString:" + firstName);
        assertEquals(firstName, "Test");
    }

在xml中设|相应的参数|可以攑օsuite下面或者test下面Q如果同名,一般test下面的定义覆盖suite定义?br />
<parameter name="first-name" value="Test"/>

    高参数化测?br />    管从一?XML 文g中抽取数据会很方便,但偶会有些试需要有复杂cdQ这些类型无法用 String 或原语值来表示。TestNG 可以通过它的 @DataProvider 注释处理q样的情c?code>@DataProvider 注释可以方便地把复杂参数cd映射到某个测试方法。例如,清单 7 中的 verifyHierarchy 试中,我采用了重蝲?buildHierarchy ҎQ它可接收一?Class cd的数? 它断aQassertingQ?code>Hierarchy ? getHierarchyClassNames() Ҏ应该q回一个适当的字W串数组Q?br />
package test.com.acme.da.ng;

import java.util.Vector;

import static org.testng.Assert.assertEquals;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.acme.da.hierarchy.Hierarchy;
import com.acme.da.hierarchy.HierarchyBuilder;

public class HierarchyTest {

@DataProvider(name = "class-hierarchies")
public Object[][] dataValues(){
return new Object[][]{
{Vector.class, new String[] {"java.util.AbstractList",
"java.util.AbstractCollection"}},
{String.class, new String[] {}}
};
}

@Test(dataProvider = "class-hierarchies")
public void verifyHierarchy(Class clzz, String[] names)
throws Exception{
Hierarchy hier = HierarchyBuilder.buildHierarchy(clzz);
assertEquals(hier.getHierarchyClassNames(), names,
"values were not equal");
}
}

     当然q有一些其他的Ҏ,׃一一详细说明了,有兴可以参考相应的testNG文档?br />      JUnit 4 ?TestNG 在表面上是相似的。然而,设计 JUnit 的目的是Z分析代码单元Q?TestNG 的预期用途则针对高񔋹试。对于大型测试套Ӟ我们不希望在某一Ҏ试失败时得重新q行数千Ҏ试,TestNG 的灵zL在q里ؓ有用。这两个框架都有自己的优势,您可以随意同时用它们?

]]>
Junit 4新的Ҏ?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/zyl/archive/2006/10/03/73255.html</guid><wfw:comment>http://www.aygfsteel.com/zyl/comments/73255.html</wfw:comment><comments>http://www.aygfsteel.com/zyl/archive/2006/10/03/73255.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.aygfsteel.com/zyl/comments/commentRss/73255.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/zyl/services/trackbacks/73255.html</trackback:ping><description><![CDATA[    JUnit 4 已经出来很久了,基本上很多ide都开始支持,当然Z兼容性,一直不太敢用。以前都是懒得写单元试Q大多数的时候都? System.out.print。不q现在已l是试驱动的时代了Qؓ了保持一个良好的习惯Q还是需要好好的写写单元试。断aq比 System.out.print有用?br />     看了几篇文章之后Q对JUnit4已经有了基本的概念了。其实很多特性,testNg都已l实CQ挺讨厌testNg的xml文gQ不qtestNg的灵zL还是强大,对于大面U的lg试比较适合?br />     JUnit 4应该说是使用新的架构写的Q用了很多java5的新Ҏ?br />     一个最关键的改变,试c,可以不用l承那该ȝ<span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">TestCase?试c,可以更加灉|Q方法的定义不需要在前面增加test了?br />     对于试cL_只需要做以下单的动作Q?br />     增加一个@TestQ用于标注相应的试Ҏ。用Assertc,来进行断a?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来说Q以后可以不用再l承q两个方法了。可以用自定义的方法,只需要在前面增加@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 /> q且可以注释多个Ҏ?br /><br />     当然JUnit4 <span style="font-size: 12pt; font-family: 宋体;">也引入了一?span lang="EN-US"> JUnit 3 </span>中没有的新特性:c范围的 <span lang="EN-US">setUp() </span>?<span lang="EN-US">tearDown() </span>Ҏ。Q何用 <span lang="EN-US">@BeforeClass </span>注释的方法都在该类中的试Ҏq行之前刚好q行一ơ,而Q何用 <span lang="EN-US">@AfterClass </span>注释的方法都在该类中的所有测试都q行之后刚好q行一ơ?br />     </span><span style="font-size: 12pt; font-family: 宋体;">?如,假设cM的每个测试都使用一个数据库q接、一个网l连接、一个非常大的数据结构,或者还有一些对于初始化和事情安排来说比较昂늚其他资源。不要在? 个测试之前都重新创徏它,您可以创建它一ơ,q还原它一ơ。该Ҏ得有些测试案例运行v来快得多?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>中的最大改q。旧式的异常试是在抛出异常的代码中攑օ <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: 宋体;">该方法不仅难看,而且试图挑战代码覆盖工具Q因Z测试是通过q是p|QL一些代码不被执行?/span><span style="font-size: 12pt; font-family: 宋体;">?span lang="EN-US"> JUnit 4 </span>中,您现在可以编写抛出异常的代码Qƈ使用注释来声明该异常是预期的Q? <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: 宋体;">    如果该异常没有抛出(或者抛Z一个不同的异常Q,那么试将p|。但是如果您惌试异常的详l消息或其他属性,则仍焉要用旧式的 <span lang="EN-US">try-catch </span>样式?br /></span><a name="N101BE"><span style="font-size: 12pt; font-family: 宋体;">    试性能 是单元测试最为痛苦的斚w之一?span lang="EN-US">JUnit 4 </span>没有完全解决q个问题Q但是它对这个问题有所帮助。测试可以用一个超时参数来注释。如果测试运行的旉过指定的毫U数Q则试p|?/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("http://*");<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 /> 基本的特性就q么多,q些功能其实都可以在testNg中找到。不qJUnitq是不错的,对于单元试来说Q这是首选的?br /><br /> 当然Z兼容性,<span style="font-size: 12pt; font-family: 宋体;">Z?span lang="EN-US"> JUnit 4 </span>试可以q行?span lang="EN-US"> JUnit 3 </span>环境中,可以它们包装在 <span lang="EN-US">JUnit4TestAdapter </span>中。将下面的方法添加到您的<span lang="EN-US"> JUnit 4 </span>试cM应该p够了Q?<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.aygfsteel.com/zyl/aggbug/73255.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/zyl/" target="_blank">布衣?/a> 2006-10-03 10:36 <a href="http://www.aygfsteel.com/zyl/archive/2006/10/03/73255.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EasyMock 2 使用指南http://www.aygfsteel.com/zyl/archive/2006/09/20/70897.html布衣?/dc:creator>布衣?/author>Wed, 20 Sep 2006 12:38:00 GMThttp://www.aygfsteel.com/zyl/archive/2006/09/20/70897.htmlhttp://www.aygfsteel.com/zyl/comments/70897.htmlhttp://www.aygfsteel.com/zyl/archive/2006/09/20/70897.html#Feedback1http://www.aygfsteel.com/zyl/comments/commentRss/70897.htmlhttp://www.aygfsteel.com/zyl/services/trackbacks/70897.html 关于单元试Q模拟对象一直是不可~少的,其对于复杂的应用来说?br />       q么多的模拟对象框架中,个h觉得比较好用的当属EasyMock了。当然JMock也不错?br />       下面单介l一下EasyMock 。(基本译EasyMock的文档,可能有些地方不是很恰当)
     
       EasyMock 2
主要用于l指定的接口提供模拟对象?/span>

模拟对象只是模拟领域代码直接的部分行为,能检是否他们如定义中的被用。?/span> Mock 对象Q来模拟合作接口Q有助于隔离试相应的领域类?/span>

创徏和维?/span> Mock 对象l常是繁琐的dQƈ且可能会引入错误?/span> EasyMock 2 动态?/span> Mock 对象Q不需要创建,q且不会产生代码?/span>

有利的方面:

不需要手工写cL处理 mock 对象?/span>

支持安全的重?/span> Mock 对象Q测试代码不会在q行期打断当重新命名Ҏ或者更Ҏ法参数?/span>

支持q回值和例外?/span>

支持察方法调用次序,对于一个或者多?/span> Mock 对象?/span>

不利的方面: 2.0 仅用于 java 2 版本 5.0 或者以?/font>
    

    以一个例子来说明如何使用EasyMock:
   假设有一个合作接?span style="font-size: 10.5pt; color: black;" lang="EN-US">CollaboratorQ?br />           
package org.easymock.samples;
 
public interface Collaborator {
    void documentAdded(String title);
    void documentChanged(String title);
    void documentRemoved(String title);
    byte voteForRemoval(String title);
    byte[] voteForRemovals(String[] title);
}

我们主要的测试类为:
package org.easymock.samples;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ClassUnderTest {
    private Set<Collaborator> listeners = new HashSet<Collaborator>();
    private Map<String, byte[]> documents = new HashMap<String, byte[]>();
    public void addListener(Collaborator listener) {
        listeners.add(listener);
    }
    public void addDocument(String title, byte[] document) {
        boolean documentChange = documents.containsKey(title);
        documents.put(title, document);
        if (documentChange) {
            notifyListenersDocumentChanged(title);
        } else {
            notifyListenersDocumentAdded(title);
        }
    }
    public boolean removeDocument(String title) {
        if (!documents.containsKey(title)) {
            return true;
        }
        if (!listenersAllowRemoval(title)) {
            return false;
        }
        documents.remove(title);
        notifyListenersDocumentRemoved(title);
        return true;
    }
    public boolean removeDocuments(String[] titles) {
        if (!listenersAllowRemovals(titles)) {
            return false;
        }
        for (String title : titles) {
            documents.remove(title);
            notifyListenersDocumentRemoved(title);
        }
        return true;
    }
    private void notifyListenersDocumentAdded(String title) {
        for (Collaborator listener : listeners) {
            listener.documentAdded(title);
        }
    }
    private void notifyListenersDocumentChanged(String title) {
        for (Collaborator listener : listeners) {
            listener.documentChanged(title);
        }
    }
    private void notifyListenersDocumentRemoved(String title) {
        for (Collaborator listener : listeners) {
            listener.documentRemoved(title);
        }
    }
    private boolean listenersAllowRemoval(String title) {
        int result = 0;
        for (Collaborator listener : listeners) {
            result += listener.voteForRemoval(title);
        }
        return result > 0;
    }
    private boolean listenersAllowRemovals(String[] titles) {
        int result = 0;
        for (Collaborator listener : listeners) {
            result += listener.voteForRemovals(titles);
        }
        return result > 0;
    }
}

W一?/span>Mock 对象

我们创?/span>test case q且围绕此理解相关的EasyMock 包的功能。第一个测试方法,用于是否删除一个不存在的文档,不会发通知l合作类?br />          
package org.easymock.samples;
 
import junit.framework.TestCase;
 
public class ExampleTest extends TestCase {
 
    private ClassUnderTest classUnderTest;
    private Collaborator mock;
 
    protected void setUp() {
        classUnderTest = new ClassUnderTest();
        classUnderTest.addListener(mock);
    }
 
    public void testRemoveNonExistingDocument() {    
        // This call should not lead to any notification
        // of the Mock Object: 
        classUnderTest.removeDocument("Does not exist");
    }
}
    对于多数试c,使用EasyMock 2,我们只需要静态引?/span>org.easymock.EasyMock的方法?/span>      
 

import static org.easymock.EasyMock.*;

import junit.framework.TestCase;

 

public class ExampleTest extends TestCase {

 

    private ClassUnderTest classUnderTest;

    private Collaborator mock;

   

}

     

Z取得Mock 对象Q需要:

l         创徏Mock 对象从需要模拟的接口

l         记录期待的行?/span>

l         转换?/span>Mock对象Q?/span>replay状态?/span>

例如Q?/span>     
 
protected void setUp() {
        mock = createMock(Collaborator.class); // 1
        classUnderTest = new ClassUnderTest();
        classUnderTest.addListener(mock);
    }

 public void testRemoveNonExistingDocument() {
        // 2 (we do not expect anything)
        replay(mock); // 3
        classUnderTest.removeDocument("Does not exist");
    }
  

在执行第三步后,mock ?/span>Collaborator接口?/span>Mock对象Qƈ且期待没有什么调用。这意味着Q如果我们改?/span>ClassUnderTest去调用此接口的Q何方法,?/span>Mock对象会抛?/span>AssertionErrorQ?/span>

        
 
java.lang.AssertionError: 
  Unexpected method call documentRemoved("Does not exist"):
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
    at $Proxy0.documentRemoved(Unknown Source)
    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)
    at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)
    at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)
    ...

增加行ؓ

       让我们开始第二个试。如?/span>document?/span>classUnderTest增加Q我们期待调?/span>
mock.documentAdded()?span lang="EN-US">Mock对象使用document的标题作为参敎ͼ

 
 public void testAddDocument() {
        mock.documentAdded("New Document"); // 2
        replay(mock); // 3
        classUnderTest.addDocument("New Document", new byte[0]); 
    }
如果classUnderTest.addDocument("New Document", new byte[0])调用期待的方法,使用错误的参敎ͼMock对象会抛?span lang="EN-US">AssertionError:

 
java.lang.AssertionError: 
  Unexpected method call documentAdded("Wrong title"):
    documentAdded("New Document"): expected: 1, actual: 0
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
    at $Proxy0.documentAdded(Unknown Source)
    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)
    at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)
    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
    ...

同样Q如果调用多ơ此ҎQ则也会抛出例外Q?/span>

 
java.lang.AssertionError: 
  Unexpected method call documentAdded("New Document"):
    documentAdded("New Document"): expected: 1, actual: 1 (+1)
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
    at $Proxy0.documentAdded(Unknown Source)
    at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)
    at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)
    at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
    ...

验证行ؓ

       当我们指定行为后Q我们将验证实际发生的。当前的试会判断是否Mock对象会真实调用。可以调?/span>verify(mock)来山正是否指定的行ؓ被调用?/span>

 
public void testAddDocument() {
        mock.documentAdded("New Document"); // 2 
        replay(mock); // 3
        classUnderTest.addDocument("New Document", new byte[0]);
        verify(mock);
    }

如果p|Q则抛出AssertionError

期待明显数量的调?/span>

到现在,我们的测试只是调用一个简单的Ҏ。下一个测试将会检是否已l存?/span>documentDmock.documentChanged()调用。ؓ了确认,调用三次

 
public void testAddAndChangeDocument() {
        mock.documentAdded("Document");
        mock.documentChanged("Document");
        mock.documentChanged("Document");
        mock.documentChanged("Document");
        replay(mock);
        classUnderTest.addDocument("Document", new byte[0]);
        classUnderTest.addDocument("Document", new byte[0]);
        classUnderTest.addDocument("Document", new byte[0]);
        classUnderTest.addDocument("Document", new byte[0]);
        verify(mock);
    }

Z避免重复?/span>mock.documentChanged("Document"),EasyMock提供一个快h式。可以通过调用ҎexpectLastCall().times(int times)来指定最后一ơ调用的ơ数?/span>

 
 public void testAddAndChangeDocument() {
        mock.documentAdded("Document");
        mock.documentChanged("Document");
        expectLastCall().times(3);
        replay(mock);
        classUnderTest.addDocument("Document", new byte[0]);
        classUnderTest.addDocument("Document", new byte[0]);
        classUnderTest.addDocument("Document", new byte[0]);
        classUnderTest.addDocument("Document", new byte[0]);
        verify(mock);
    }

指定q回?/span>

       对于指定q回|我们通过装expect(T value)q回的对象ƈ且指定返回的|使用ҎandReturn(Object returnValue)?span lang="EN-US">expect(T value).q回的对象?/span>

例如Q?/span>

 
public void testVoteForRemoval() {
        mock.documentAdded("Document");   // expect document addition
        // expect to be asked to vote for document removal, and vote for it
        expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
        mock.documentRemoved("Document"); // expect document removal
        replay(mock);
        classUnderTest.addDocument("Document", new byte[0]);
        assertTrue(classUnderTest.removeDocument("Document"));
        verify(mock);
    } 
 
    public void testVoteAgainstRemoval() {
        mock.documentAdded("Document");   // expect document addition
        // expect to be asked to vote for document removal, and vote against it
        expect(mock.voteForRemoval("Document")).andReturn((byte) -42);
        replay(mock);
        classUnderTest.addDocument("Document", new byte[0]);
        assertFalse(classUnderTest.removeDocument("Document"));
        verify(mock);
    }
取代expect(T value)调用Q可以通过expectLastCall().来代?/span>
 expect(mock.voteForRemoval("Document")).andReturn((byte) 42);

{同?/span>

 
mock.voteForRemoval("Document");
expectLastCall().andReturn((byte) 42);

处理例外

对于指定的例?/span>(更确切的:Throwables)被抛出,?/span>expectLastCall()?span lang="EN-US">expect(T value)q回的对象,提供了方?/span>andThrow(Throwable throwable)。方法不得不被调用记录状态,在调?span lang="EN-US">Mock对象后,对于此指定了要抛出的Throwable?span lang="EN-US">


基本的方法,已经说完了,当然q不能完全说明EasyMock的用。更多的因素请参考EasyMock的文?br />http://www.easymock.org/Documentation.html


]]>
վ֩ģ壺 ˰| | Ӽ| ɽ| | ˻| | ̩| | | | Ϊ| | | | ̽| | | | Ž| | | | | ʯ| | ն| Т| | IJ| | | ¡| | | | ڻ| | | | |