几个测试用到的framework和tools

最近一阶段,由于项目的需要,粗略的看了看测试用到的几种framework和tools,胡乱写了些东西,主要针对自己对于这几种framework的理解,这里只起到抛砖引玉,具体细节请查看每个framework自己的官方网站

啊?“测试”有这么重要?<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

       

        没有进入TC前,在自己做过的一些小型项目中(或者根本不能称其为项目,只不过是自己写的一些程序)基本没有做过比较体系的测试,更不用提应用一些framework或是一些工具来进行测试,那时候的测试往往就是在一定的位置上print出结果,与预期的结果相比较,从而知道程序的对错。进入TC后,发现每一个开发团队都有各自的QA,而且有些团队QA的人数并不少于开发人员,测试的重要性在这里可见一斑。阅读了一些关于测试的文章,尤其是X-Programming的一些材料后,才认识到测试工作如此重要。“Program a little, test little, 貌似平淡无奇的一句话,但却是所有项目尤其是企业级项目成功的保证。从某种程度上说,QA肩负着比开发人员更重的使命。

        鉴于测试有如此重要的地位,而且我有可能(只是有可能而已)参与GTSS的测试项目,所以近一个星期以来一直在对“测试”进行研究。粗略的学习了一下用于测试的一些framework和工具,其中包括JUnit, JMeter, HttpUnit, JWebUnit, 并下Fund Connect近期完成的Performance Test进行了研究。

 

想把学到的东西给大家看看

 

        我的习惯是把一个阶段学习到的东西总结一下,将其变成文字,这样才能对学到的东西加深印象,也在成文过程中发现不明白不理解的地方。往往我写出的东西,都是给自己看的,加深个印象也就算了,但是这次为什么想和大家分享呢?并非炫耀自己有多么能干,学了多少东西,因为我深知看我这篇东西的人各个都比我能干,每一个人懂得都比我多。主要原因是:和大家不同,我不是做技术出身,只是单纯对技术有兴趣,想深入了解技术,由于专业知识的欠缺,肯定在学习和应用过程中会出现很多偏差,理解上也会有很多不对的地方,希望大家及时指出,我好及时更正。

       好了不多罗嗦了,开始正题!(欢迎大家拍转)

 

JUnit 单元测试的基础

 

        我可以大言不惭地说,JUnit本身是一个相当简单的框架,想必各位也对其做过一些研究,所以直接给出一个自己写的简单的例子,来说明JUnit的特点。

 

None.gif // Money.java:
None.gif

None.gif 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  Money  dot.gif {
InBlock.gif
InBlock.gif        
private int amount;
InBlock.gif
InBlock.gif        
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public Money(int i)dot.gif{
InBlock.gif
InBlock.gif               amount 
= i;
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public int amount()dot.gif{
InBlock.gif
InBlock.gif               
return amount;
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public Money addMoney(Money mon)dot.gif{
InBlock.gif
InBlock.gif               
return new Money(mon.amount()+this.amount());
InBlock.gif
InBlock.gif               
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif
//The key point here
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif        
public boolean equals(Object o)dot.gif{
InBlock.gif
InBlock.gif               
if(o instanceof Money)
InBlock.gif
InBlock.gif                       
return ((Money)o).amount() == this.amount();
InBlock.gif
InBlock.gif               
else 
InBlock.gif
InBlock.gif                       
return false;
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedBlockEnd.gif}
 
None.gif
None.gif 
None.gif
None.gif
// TestMoney.java
None.gif

None.gif 
None.gif
None.gifimport junit.framework.
* ;
None.gif
None.gif 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  TestMoney extends TestCase dot.gif {
InBlock.gif
InBlock.gif        Money m11;
InBlock.gif
InBlock.gif        Money m12;
InBlock.gif
InBlock.gif        Money m13;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected void setUp()dot.gif{
InBlock.gif
InBlock.gif               m11 
= new Money(11);
InBlock.gif
InBlock.gif               m12 
= new Money(12);
InBlock.gif
InBlock.gif               m13 
= new Money(13);
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public void testEquals()dot.gif{
InBlock.gif
InBlock.gif               Assert.assertEquals(m11,
new Money(11));
InBlock.gif
InBlock.gif               
InBlock.gif
InBlock.gif               Assert.assertEquals(m11,
new Money(11));
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public void testAdd()dot.gif{
InBlock.gif
InBlock.gif               Money m23 
= new Money(23);
InBlock.gif
InBlock.gif               Assert.assertEquals(m11.addMoney(m12),m23);
InBlock.gif
InBlock.gif               Assert.assertEquals(m11.addMoney(m12),m11);
InBlock.gif
InBlock.gif               
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public static void main(String args[]) dot.gif{
InBlock.gif
InBlock.gif               junit.textui.TestRunner.run(TestMoney.
class);
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
InBlock.gif
ExpandedBlockEnd.gif}

None.gif
None.gif

        看到这里你可能会骂我把小孩子都能写出的东西贴到这里来丢人,其实就是这么个简单的例子足以说明JUnit的运作原理。class Money重载了方法equals(), 就是为了进行Money对象之间的比较。这样的比较在JUnit中是通过断言的方式进行的,由于基础类TestCase继承于Assert类,从而继承了Assert类提供的所有断言方法。所以一句话概括,JUnit是通过断言机制进行底层对象间的比较来判断功能正确与否的。你可能会抬杠的说:“不仅是对象吧,JUnit也可以比较两个int或者其他的primitive data啊!”,但在OO的理论中,Java中的primitive data也应该是对象(如SmallTalk中的实现),但Java出于对性能的考虑,对primitive data没有采取类的实现方式,但同时也给出了各个primitive data wrapper class

最初认识到JUnit的这样的工作原理,我有些失望怀疑它能否胜任复杂的商业逻辑的测试,看到了Fund Connectperformance test中测试service部分的代码,我这样的疑虑被消除了。下面节选一段代码说明:

None.gif public   class  AdminServiceTest extends TestCase
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
InBlock.gif        
private static Log log = LogFactory.getLog(AdminServiceTest.class);
InBlock.gif
InBlock.gif        
private static ServiceFactory factory;
InBlock.gif
InBlock.gif        
protected static AdminService ds;
InBlock.gif
InBlock.gif        
private static ServiceConfigurator serviceConfig;
InBlock.gif
InBlock.gif        
private Statement stmt;
InBlock.gif
InBlock.gif        
private ResultSet rs;
InBlock.gif
InBlock.gif        
private String sConnStr;
InBlock.gif
InBlock.gif        
private String sqlStr;
InBlock.gif
InBlock.gif        
private Connection conn=null;
InBlock.gif
InBlock.gif
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//**
InBlock.gif
InBlock.gif     * Constructor for AdminServiceImplTest.
InBlock.gif
InBlock.gif     * @param arg0
InBlock.gif
ExpandedSubBlockEnd.gif     
*/

InBlock.gif
InBlock.gif    
public AdminServiceTest(String arg0)
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif
InBlock.gif        super(arg0);
InBlock.gif
ExpandedSubBlockEnd.gif    }
    
InBlock.gif
InBlock.gif             
protected void setUp() throws Exception
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif
InBlock.gif                 
//……
InBlock.gif

ExpandedSubBlockEnd.gif             }

InBlock.gif
InBlock.gif             
protected void teardown() throws Exception
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif             
dot.gif{
InBlock.gif
InBlock.gif                 
// …..
InBlock.gif

ExpandedSubBlockEnd.gif             }

InBlock.gif
InBlock.gif 
InBlock.gif
InBlock.gif             
public void testGetFundProcessors()
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif
InBlock.gif        
InBlock.gif
InBlock.gifsqlStr 
= "select distinct Fund_Processor_uid from                               FUND_PROCESSOR_INSTR_XREF ";
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif               
try dot.gif{
InBlock.gif
InBlock.gif                       rs 
= stmt.executeQuery(sqlStr);
InBlock.gif
InBlock.gif                       List result 
= (List)ds.getFundProcessors();
InBlock.gif
InBlock.gif                       
int i = 0;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                       
while(rs.next())dot.gif{
InBlock.gif
InBlock.gif                               i 
++;
InBlock.gif
ExpandedSubBlockEnd.gif                       }

InBlock.gif
InBlock.gif                       assertEquals(i, result.size());
InBlock.gif
InBlock.gif                       
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif               }
 catch (SQLException e) dot.gif{
InBlock.gif
InBlock.gif                       e.printStackTrace();
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif               }
 catch (AdminServiceException e) dot.gif{
InBlock.gif
InBlock.gif                       e.printStackTrace();
InBlock.gif
ExpandedSubBlockEnd.gif               }
       
InBlock.gif
ExpandedSubBlockEnd.gif               }

InBlock.gif
InBlock.gif               
//……
InBlock.gif

ExpandedBlockEnd.gif            }

None.gif
None.gif


 

         从这个例子中可以看到,无论是多么复杂的逻辑(testGetFundProcessors)最终都能转化成底层对象通过断言的比较(红色字体部分)。“Everything is object. , JUnit的工作原理决定了它应该是单元测试的基础。

         另外,我也看了一下JUnit的源码,代码并不是很多多,由于应用了一些模式,使其结构设计较好。例如:TestCase类中,在设计run()方法的继承问题时,应用了Template Method Pattern 对于多个test方法,要有针对性地生成相应的TestCase,应用了Adapter Pattern;等等。大家有兴趣的,可以对其源码进行研究。

 

强大的测试工具JMeter

        我看过的所有的Apache的项目,都很成功。JMeter也不例外,说其强大,我个人认为有以下三个原因:

1、 较为友好的图形用户界面,易于测试人员使用,只要明白其中的原理用JMeter作测试是件愉快的事情而且它能够方便的生成测试脚本。

2、 ThreadGroup概念的引进,这个概念在JMeter是相当重要的,之所以JMeter能够完成对各种不同服务器的压力测试与性能测试,也仰仗着ThreadGroup。在一个ThreadGoup中可以规定应用的线程数量(Number of Threads每一个线程代表一个用户),也可以规定用户行为的重复次数(loop count)。在企业级应用的测试中,模拟多个用户同时执行操作或同时处理数据的操作,利用ThreadGroup可以轻松实现。

3、 JMeter将大量的Test Target作了非常好的封装,用户可以直接使用这些封装好的部件,大大减少了测试的工作量。比如测试WebService用的WebService SOAP Request 测试网页的HttpRequest,测试数据库连接的JDBC Request等等。测试工作进而简化成了选择组建,将各个组建有逻辑的组织在一起的过程。

        对于JMeter的强大以及其应用方法,因为大家都懂,所以我在这里不多说了。下面谈谈个人认为JMeter的不足之处。为了更清楚的说明这个问题,我将结合Fund Connect项目中,对于Server Performance Test的一些JMeter脚本进行阐述。其中的一个Requirement如下:

 

Investors submit trades via GUI

 

Description: 15 investors log into FundConnect via GUI. Each investor submits 20 orders via a file upload.

Precondition: 20 investor institutions and 20 investors (one investor per investor institution) are set up in FundConnect.

Step: A JMeter script will execute the following steps: Log In à Start in Investor Home à Upload Multiple Orders à Select upload file à Submit file à Return to Investor Home.

Note: Each investor should upload a different file. The script should record the average time to execute the entire loop (Investor Home to Investor Home).

 

        想必大家对这个需求再清楚不过了(毕竟刚完成测试工作)。用JMeter测试中有一个关键的组件(其余省略不说了):

HttpRequest

Name/fundconnect/FCUploadOrdersServlet

 

Send Parameters With the Request

Name                        value

thisURL                    /inv/upload_orders.jsp

submitURL              /inv/upload_orders_summary.jsp

cancelURL              /adm/index.jsp

 

Send a file with request

File name: D:\datatest\datatest\20order_upload\testdata\uploadorders_20_acct1.csv

Parameter Name: uploadfile

MIME Type: application/octet-stream

 

     这个Request是向FCUploadOrdersServlet发出,其间传递了三个参数和一个文件,完成上传order文件的工作。这个需求到此也就结束了,但大家有没有想过,如果把需求改成: 15 investors log into FundConnect via GUI. Each investor submits 20 orders via web page. 即如果要求这15个投资者通过web(非上传文件方式)递交20不同的order,模拟这样的测试该如何进行呢?JMeter针对这样的Web页面操作的测试,实现起来比较复杂。(如果谁认为不对,可以联系我,把你的方法告诉我)。我个人认为做Web Application页面上的功能测试,使用下面谈到的两个框架,实现起来比较简单。

 

Web Application自动化测试FrameWorksHttpUnit    JWebUnit

 

HttpUnit本身并没有测试功能, 说白了, 它不过包含了一些类库, 可以用来模拟出一个浏览器(WebConversation)并可以模拟用户在网页上的多种行为。HttpUnit没有测试的功能,所以它要结合JUnit来完成Web测试的工作,例如下面是一段简单的代码:

None.gif import junit.framework.TestCase;
None.gif
None.gifimport com.meterware.httpunit.WebResponse;
None.gif
None.gifimport com.meterware.httpunit.WebConversation;
None.gif
None.gifimport com.meterware.httpunit.WebForm;
None.gif
None.gifimport com.meterware.httpunit.WebRequest;
None.gif
None.gif 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  SearchExample extends TestCase  dot.gif {
InBlock.gif
InBlock.gif 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public void testSearch() throws Exception dot.gif{
InBlock.gif
InBlock.gif      
//模拟浏览器
InBlock.gif

InBlock.gif      WebConversation wc 
= new WebConversation();
InBlock.gif
InBlock.gif      
//对google主页发出request,并得到response
InBlock.gif

InBlock.gif      WebResponse resp 
= wc.getResponse( "http://www.google.com");
InBlock.gif
InBlock.gif      
//从Response中抽取出第一个table
InBlock.gif

InBlock.gif      WebForm form 
= resp.getForms()[0];
InBlock.gif
InBlock.gif      
//在搜索的text field called q中填写”HttpUnit”
InBlock.gif

InBlock.gif      form.setParameter(
"q""HttpUnit");
InBlock.gif
InBlock.gif      
//点击提交按钮
InBlock.gif

InBlock.gif      WebRequest req 
= form.getRequest("btnG");
InBlock.gif
InBlock.gif      resp 
= wc.getResponse(req);
InBlock.gif
InBlock.gif      
//通过反馈回来的response来判断叫做HttpUnit的link是否存在
InBlock.gif

InBlock.gif      assertNotNull(resp.getLinkWith(
"HttpUnit"));
InBlock.gif
InBlock.gif      
//模拟点击连接的功能
InBlock.gif

InBlock.gif      resp 
= resp.getLinkWith("HttpUnit").click();
InBlock.gif
InBlock.gif      
//通过title来判断返回的reponse的title是否为HttpUnit
InBlock.gif

InBlock.gif      assertEquals(resp.getTitle(), 
"HttpUnit");
InBlock.gif
InBlock.gif      assertNotNull(resp.getLinkWith(
"User's Manual"));
InBlock.gif
ExpandedSubBlockEnd.gif   }

InBlock.gif
ExpandedBlockEnd.gif}

None.gif
None.gif


你可以发现上面的一个例子, 已经完成了对于在google中查找HttpUnit关键字的测试。

在此基础上,JWebUnit更近一步,它实际上是建立在HttpUnitJUnit框架之上,将二者功能结合、重构后的产物。同时,JWebUnit提供了更加易用的API来模拟用户对web界面的操作,同样是上面的代码,JWebUnit的实现如下:

None.gif import net.sourceforge.jwebunit.WebTestCase;
None.gif
None.gif 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  JWebUnitSearchExample extends WebTestCase  dot.gif {
InBlock.gif
InBlock.gif 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public JWebUnitSearchExample(String name) dot.gif{
InBlock.gif
InBlock.gif      super(name);
InBlock.gif
ExpandedSubBlockEnd.gif   }

InBlock.gif
InBlock.gif 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public void setUp() dot.gif{
InBlock.gif
InBlock.gif      getTestContext().setBaseUrl(
"http://www.google.com");
InBlock.gif
ExpandedSubBlockEnd.gif   }

InBlock.gif
InBlock.gif 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public void testSearch() dot.gif{
InBlock.gif
InBlock.gif      beginAt(
"/");
InBlock.gif
InBlock.gif      setFormElement(
"q""httpunit");
InBlock.gif
InBlock.gif      submit(
"btnG");
InBlock.gif
InBlock.gif      clickLinkWithText(
"HttpUnit");
InBlock.gif
InBlock.gif      assertTitleEquals(
"HttpUnit");
InBlock.gif
InBlock.gif      assertLinkPresentWithText(
"User's Manual");
InBlock.gif
ExpandedSubBlockEnd.gif   }

InBlock.gif
ExpandedBlockEnd.gif}

None.gif
None.gif



      我相信不用加任何注释, 大家也可以轻松的理解每一步操作。接下来我应用了JWebUnit测试了Fund Connect web页面上的一些功能, 下面列出了以Admin身份登陆, 对增加Fund这样一个功能的测试:

 

None.gif import net.sourceforge.jwebunit.WebTestCase;
None.gif
None.gifimport org.xml.sax.SAXException;
None.gif
None.gifimport com.meterware.httpunit.HttpUnitOptions;
None.gif
None.gifimport com.meterware.httpunit.WebConversation;
None.gif
None.gifimport com.meterware.httpunit.WebResponse;
None.gif
None.gif 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  AdminTest extends WebTestCase dot.gif {
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public static void main(String [] args)dot.gif{
InBlock.gif
InBlock.gif               junit.swingui.TestRunner.run(AdminTest.
class);
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public void setUp()dot.gif{
InBlock.gif
InBlock.gif               
//get rid of Java Script check
InBlock.gif

InBlock.gif               HttpUnitOptions.setExceptionsThrownOnScriptError(
false);
InBlock.gif
InBlock.gif               
//set the base url for this test
InBlock.gif

InBlock.gif               getTestContext().setBaseUrl(
"http://tcsunfire04.zdus.com:9220");
InBlock.gif
InBlock.gif               
//set username and password to get through SiteMinder         authentication
InBlock.gif

InBlock.gif               getTestContext().setAuthorization(
"bos.ssb.dwf""123");
InBlock.gif
InBlock.gif               
//set the cookie required
InBlock.gif

InBlock.gif                getTestContext().addCookie(
"SMCHALLENGE""YES");
InBlock.gif
InBlock.gif 
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif               
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public void testSiteMinder()dot.gif{
InBlock.gif
InBlock.gif               
//test wether test can get through SiteMinder or not
InBlock.gif

InBlock.gif               beginAt(
"/fundconnect/adm");
InBlock.gif
InBlock.gif               assertTitleEquals(
"Global Link Fund Connect");
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//*
InBlock.gif
InBlock.gif         *Test for adding a new Fund
InBlock.gif
InBlock.gif         *Fund long name: star's Fund
InBlock.gif
InBlock.gif         *Fund short name: starFund
InBlock.gif
InBlock.gif         *Fund Provider: Starhero
InBlock.gif
ExpandedSubBlockEnd.gif         
*/

InBlock.gif
InBlock.gif        
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public void testAddFund()dot.gif{
InBlock.gif
InBlock.gif               beginAt(
"/fundconnect/adm/maintfunds_funddet.jsp?add=new");
InBlock.gif
InBlock.gif               
//Fill in the add fund form
InBlock.gif

InBlock.gif               setFormElement(
"fundInstrumentLongName","star's fund");
InBlock.gif
InBlock.gif               setFormElement(
"fundInstrumentName","starFund");
InBlock.gif
InBlock.gif               setFormElement(
"fundInstrumentCode","123567");
InBlock.gif
InBlock.gif               selectOption(
"fundCodeType","ISO");
InBlock.gif
InBlock.gif               selectOption(
"timeZone","(GMT+08:00) Asia/Shanghai");
InBlock.gif
InBlock.gif               selectOption(
"fundProviderIndex","Starhero");
InBlock.gif
InBlock.gif               selectOption(
"settlementCurrency","USD -- US Dollar");
InBlock.gif
InBlock.gif               selectOption(
"partialShares","No");
InBlock.gif
InBlock.gif               setFormElement(
"contactName","Brooks");
InBlock.gif
InBlock.gif               setFormElement(
"contactPhoneNumber","13989472700");
InBlock.gif
InBlock.gif               selectOption(
"investmentType","Short Term");
InBlock.gif
InBlock.gif               selectOption(
"assetClass","EQUITY");
InBlock.gif
InBlock.gif               selectOption(
"industry","DEVELOPED");
InBlock.gif
InBlock.gif               selectOption(
"countryRegion","UNITED STATES");
InBlock.gif
InBlock.gif               selectOption(
"benchmark","AUD LIBID");
InBlock.gif
InBlock.gif               selectOption(
"domicileCountry","United States");
InBlock.gif
InBlock.gif               setFormElement(
"defaultPrice","50");
InBlock.gif
InBlock.gif               
InBlock.gif
InBlock.gif               selectOption(
"fundInstrumentCountries","United States");
InBlock.gif
InBlock.gif               selectOption(
"institutionSelect","lon.ssb");
InBlock.gif
InBlock.gif                       
InBlock.gif
InBlock.gif               setFormElement(
"cutoff","22:00");
InBlock.gif
InBlock.gif               selectOption(
"cutoffType","Hard Cutoff");
InBlock.gif
InBlock.gif               
//submit the form
InBlock.gif

InBlock.gif               submit(
"sbmtSubmit");
InBlock.gif
InBlock.gif                
//According to the fund's long name and fund's short name to assert
InBlock.gif
InBlock.gif                
//that fund is added
InBlock.gif

InBlock.gif                assertTextPresent(
"star's fund");
InBlock.gif
InBlock.gif                assertTextPresent(
"starFund");
InBlock.gif
InBlock.gif               
InBlock.gif
ExpandedSubBlockEnd.gif        }
    
InBlock.gif
ExpandedBlockEnd.gif}

None.gif
None.gif

 

        由此看出, JWebUnit可以完成Web页面上复杂应用的测试。可以在以后的项目中逐渐使用。

 

 写在后面     

 

        首先得感谢你,能够耐得住性子看到这里,浪费了你宝贵的时间深表歉意。以上就是我对近期对于测试工具及FrameWork研究的小结,有不对或不妥之处还请指正。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                                                                                                                                   小川

          <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><date year="2005" day="12" month="7">7/12/2005</date>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值