用java构建企业级自动化框架(首篇-制定测试者使用语言1)

来源:互联网 发布:java sleep 编辑:程序博客网 时间:2024/04/30 06:41

这个是我后来写的一本书,http://www.ituring.com.cn/minibook/10775。这个是我后来找到的自动化完美解决方案。


首先我们谈论下Automation语言组织管理,因为一个Automation 的框架要使用它,就得用语言去驱动它,在一些自动化的软件中,你会见到那种不需要写语言,直接录制回放就去执行你脚本的自动化软件,但其实在录制的过程中,它只是智能的代替你生成脚本化语言,而这语言很多时候是没有你手写的健壮(即不容易出错)。你要时不时去修改它,修改的时候你肯定必须懂得脚本语言。

我们先看一种方法,用XML去写自己的XML表达式语言然后去驱动相关的Java类或者Java方法执行.


首先,我们先说一种设计模式,叫模板方法,它是用公共的父类去制定好子类的行为,就像上一篇Junit示例那样,先定好之类可执行的方法setup()、teardown(),并在父类中指定好他们的执行顺序;就是怎么说我用父类先做好模板,子类只要继承这个模板写出自己的特定业务实现就行了。用它就像大学时你考四六级英语用的作文模板一样的用就行了。

好了,开始

首先制定一个模板类,这个模板所要做的工作是限定子类只能用什么方法,并且规定好这些方法的执行顺序。

public abstract class Demo{

    public abstract void setUp();

      public abstract void getValueFromXml();

      public abstract void execute(Element e);

      public abstract void tearDown();

     

      public final void run(Element e){

            setUp();

            getValueFromXml(e);

            execute();

            tearDown();      

      }

}

分析一下这个方法,里面的setUp()和tearDown()是每个子类都会用到且用的方法一模一样,所以也可以抽出来作为第二级模板

public abstract class JSPDemo extends Demo{

 

    SeleniumServer server;
    Selenium selenium;
    public void setUp() {

        RemoteControlConfiguration cfg=new RemoteControlConfiguration();
        
        try {
            server=new SeleniumServer(cfg);
            server.boot();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

 

 

 

    public void tearDown() {
        selenium.close();
        server.stop();
    }

 

}

接着就简单了,最后的子类即实际应用类只要继承这个第二级类就行了

 

public class FirstDemo extends JSPDemo {

     

 

      public void getValueFromXml(Element e) {

            System.out.println("getValueFromXml");

           

      }

 

      @Override

      public void execute() {

      System.out.println("execute");

           

      }

     

 

}

这样以后每种实现类都以这种方式书写就行了。


在转回正题,我们接着讨论xml,首先我们看下面一个test.xml.

<?xml version="1.0" encoding="UTF-8"?>
<Script>   
<FirstDemo name="testjingdongcom" password="jingdong" productId="286048"/>

<JingDongCustomerService name="admin" password="admin"/>   
 
</Script> 

接着我们看下解析它的类文件



import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class AnalyzeScript {
    private String xmlRoad;
     private Document doc = null;

    /**
     * @param:String(xmlRoad)
     * 在构造器中导入xml所在的路径
     */
    public AnalyzeScript(String xmlRoad) {
        this.xmlRoad = xmlRoad;
    }
    
    /**
     * @param:String(xmlRoad)
     * 读xml.
     */
    public void parse(String xmlRoad) throws Exception {
        File scriptFile = new File(xmlRoad);
        if (!scriptFile.exists()) {
            throw new FileNotFoundException("the script file does not exists. ");
        } else if (scriptFile.isDirectory()) {
            throw new IllegalArgumentException(
                    "the script file is not a file. ");
        }

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        doc = db.parse(scriptFile);
    }
    
    /**
     * @param:String(xmlRoad)
     * @return NodeList
     * 获得xml其中一个节点.
     */
    public NodeList analyzeXmlForGetALlNodeName(){
        Node fatherNode=null;
        try {
            parse(xmlRoad);
            Element root = doc.getDocumentElement();
             NodeList nodeList = doc.getElementsByTagName("Script");
            System.out.println(root.getNodeName());
            fatherNode = nodeList.item(0);
                   
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return fatherNode.getChildNodes();
    }
    
    /**
     * @param:Element String
     * @return 根据传入的element和属性名得到属性值。
     *
     */
    public static String analyzeXML(Element e,String attributs){
        String attr=null;
        try {
             if(e.hasAttributes()){
              attr=e.getAttribute(attributs);
             }
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
         return attr;
        
    }    

}


那解析好xml后我们干什么呢?看下面代码,把xml节点名字和java类对应起来,看我们的下面这段代码,通过反射对应找到相对应得java类


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


public class ReflectJavaClassRun {
    private String xmlRoad;
    public ReflectJavaClassRun(String xmlRoad){
        this.xmlRoad=xmlRoad;
        
    }
    private List scriptNodeList=new ArrayList();
    
    /**
     * 通过反射找到对应的java类
     */
    public void ReflectJavaClass() throws ClassNotFoundException,Exception{
    AnalyzeScript as=new AnalyzeScript(xmlRoad);
    NodeList childNode=as.analyzeXmlForGetALlNodeName();     
    for(int i=0;i<childNode.getLength(); i++){
        //得到xml节点
        Node node=childNode.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {        
             Element e=(Element)node;
        //通过反射找到对应的java类
        Class clazz=Class.forName(e.getNodeName());
         Demo instance=(Demo)clazz.newInstance();
         //得到刚才模板模式中定义好的run方法,注意new Class[] { Element.class }和下面的m.invoke(instance,e)都是表示在反射中如何把参数传入对应的方法中。
         Method m = clazz.getMethod("run", new Class[] { Element.class });
        m.invoke(instance,e);
        }
    }    
    }


好,那我们看最后一步,它调用的FirstDemo类是什么样子。


import org.w3c.dom.Element;
import com.thoughtworks.selenium.DefaultSelenium;


public class FirstDemo extends JSPDemo{

    private String name;
    private String password;
    private String productId;
    
    
       public void getValueFromXml(Element e) {
      //把传入的节点中属性名为name的属性值取出来。
        name=AnalyzeScript.analyzeXML(e, "name");
        System.out.println(name);

     //把传入的节点中属性名为passeword的属性值取出来。
        password=AnalyzeScript.analyzeXML(e, "password");

     //把传入的节点中属性名为productId的属性值取出来。
        productId=AnalyzeScript.analyzeXML(e, "productId");
      }
      


      public void execute()  {
            try {
            selenium=new DefaultSelenium("localhost",4444,"*firefox","http://www.360buy.com/");
            selenium.start();
            selenium.windowMaximize();
            selenium.setTimeout("600000");
            selenium.open("http://www.360buy.com/product/"+productId+".html");
            Thread.sleep(20000);
            
            selenium.click("xpath=id('InitCartUrl')");
            Thread.sleep(20000);
            selenium.click("xpath=id('GotoShoppingCart')");
            Thread.sleep(20000);
            selenium.click("xpath=id('gotoOrderInfo')");
            Thread.sleep(5000);
            selenium.type("xpath=id('loginname')", name);
            selenium.type("xpath=id('loginpwd')", password);
            selenium.click("xpath=id('loginsubmitframe')");
            Thread.sleep(10000);
            selenium.type("xpath=id('consignee_addressName')", "张俊卿");
            selenium.select("xpath=id('consignee_province')", "index=2");
            Thread.sleep(5000);
            selenium.select("xpath=id('consignee_city')", "普陀区*");
            Thread.sleep(10000);
            selenium.select("xpath=id('consignee_county')", "桃浦新村*");
            selenium.type("xpath=id('consignee_address')", "上海西站");
            selenium.type("xpath=id('consignee_message')", "13999999999");
            selenium.click("xpath=id('part_consignee')//div[@class='footer']/input");
            Thread.sleep(5000);
            selenium.check("xpath=id('IdPaymentType1')");
            String s=selenium.getText("xpath=id('part_cart')//div[@class='middle']//tr[@class='align_Center']/td[1]");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
      }
 }

呵呵,还记得模板方法中定义的这些方法调用的顺序吗。他们会按照setUp()- getValueFromXml(e)-execute()- tearDown()的顺序先后执行。

检查一下上面的方法正确与否?运行

    public static void main(String[] args) {
        ReflectJavaClassRun rj=new ReflectJavaClassRun("src\\test.xml");
        try {
            rj.ReflectJavaClass();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }


执行完后,他们接着找xml中写出的第二个类JingDongCustomerService去执行,JingDongCustomerService类如何使用模板的就不详细说了,只要继承JSPDemo就行了。


未完待续-下面小节会接着说验证是如何在xml中定义和在java类中如何使用它,对数据库的调用xml的参考格式在下面之下章节也会说到。最后说下这种方法的优缺点和改进方法。








原创粉丝点击