首页 > 代码库 > Android WebApp & NativeApp 适配测试自动化平台GoGo实现 东海陈光剑

Android WebApp & NativeApp 适配测试自动化平台GoGo实现 东海陈光剑

Android WebApp & NativeApp 适配测试自动化平台GoGo实现
  东海陈光剑 
  2014年3月6日 18:27:55

源代码:

https://github.com/universsky/AndroidAutomationTestUniverssky.git 

GoGo平台架构:



运行结果:


http://10.73.72.122:88/report.html?run_stamp=20140306052855&sec=336&min=5



http://10.125.1.58:88/report.html?run_stamp=20140428073427?min=3?sec=214 



性能分析CPU%:( 用highcharts做成图形化的报告形式 )




运行日志:



生成报告代码:

资源上传服务器:

/**
 * Upload.java etao.test.fileload UploadFileToServer 下午1:38:59 2014年4月20日 2014
 */

package etao.test.fileload;

/**
 * @author 东海陈光剑
 *  2014年4月20日 下午1:38:59 
 */

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@SuppressWarnings("serial")
public class Upload extends HttpServlet {
    private String uploadPath = "C:\\autoTest\\httpd\\htdocs\\img"; // 上传文件的目录
    private String tempPath = "c:\\buffer\\"; // 临时文件目录
    File tempPathFile;

    @SuppressWarnings("unchecked")
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        try {
            // Create a factory for disk-based file items
            DiskFileItemFactory factory = new DiskFileItemFactory();

            // Set factory constraints
            factory.setSizeThreshold(4096); // 设置缓冲区大小,这里是4kb
            factory.setRepository(tempPathFile);// 设置缓冲区目录

            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload(factory);

            // Set overall request size constraint
            upload.setSizeMax(4194304); // 设置最大文件尺寸,这里是4MB

            List<FileItem> items = upload.parseRequest(request);// 得到所有的文件
            Iterator<FileItem> i = items.iterator();
            while (i.hasNext()) {
                FileItem fi = (FileItem) i.next();
                String fileName = fi.getName();
                if (fileName != null) {
                    File fullFile = new File(fi.getName());
                    File savedFile = new File(uploadPath, fullFile.getName());
                    fi.write(savedFile);
                }
                System.out.println(fileName + " upload successfully!");
            }
            // System.out.println("upload succeed");
        } catch (Exception e) {
            // 可以跳转出错页面
            e.printStackTrace();
        }
    }

    public void init() throws ServletException {
        File uploadFile = new File(uploadPath);
        if (!uploadFile.exists()) {
            uploadFile.mkdirs();
        }
        File tempPathFile = new File(tempPath);
        if (!tempPathFile.exists()) {
            tempPathFile.mkdirs();
        }
    }
}

public static void genReport(String run_stamp, String runningSec,
            String runningMin) {
        /**
         * 调用系统默认浏览器打开链接
         * http://10.73.72.122:88/report.html?run_stamp=20140302023811
         * &sec=250&min=4
         */
        if (java.awt.Desktop.isDesktopSupported()) {
            try {
                String reportUriStr = "http://10.73.72.122:88/report.html?run_stamp="
                        + run_stamp
                        + "&sec="
                        + runningSec
                        + "&min="
                        + runningMin;
                // 创建一个URI实例
                java.net.URI reportUri = java.net.URI.create(reportUriStr);
                // String uri1Str =
                // "http://10.73.72.122:8080/Report/go?run_stamp="
                // + run_stamp;
                //
                // java.net.URI uri1 = java.net.URI.create(uri1Str);
                // 获取当前系统桌面扩展
                java.awt.Desktop dp = java.awt.Desktop.getDesktop();
                // 判断系统桌面是否支持要执行的功能
                if (dp.isSupported(java.awt.Desktop.Action.BROWSE)) {
                    // 获取系统默认浏览器打开链接
                    dp.browse(reportUri);
                    // dp.browse(uri1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

report.html放到Apache httpd Server下面:D:\Apache2.2\htdocs

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>适配测试报告</title>
    <script src="http://g.tbcdn.cn/kissy/k/1.4.0/seed-min.js"></script>
<style type="text/css">    
body {
 background-color: #EEFFFF;  
}                              
p.serif{font-family:"Times New Roman",Georgia,Serif}
p.sansserif{font-family:Arial,Verdana,Sans-serif} 
       
</style>                      
   
   
</head>

<body class="serif">
    <br><br><br><br>
    <h1 align="center"style=font-family:微软雅黑>一淘android客户端适配测试报告</h1>
   
              <p align="right">
                <label for="issue_issue_author_id">联系人:陈光剑</label>
                 <a href="http://www.taobao.com/webww/ww.php?ver=3&touid=universsky1&siteid=cntaobao&status=2&charset=utf-8" class="inline-item" target="_blank" title="universsky1"><img alt="universsky1" border="0" src="http://amos.alicdn.com/realonline.aw?v=2&uid=universsky1&site=cntaobao&s=2&charset=utf-8" /></a><a href="http://amos.alicdn.com/msg.aw?v=2&uid=universsky1&site=cnalichn&s=11&charset=UTF-8" class="inline-item" target="_blank" title="universsky1"></a>
              </p>
   
    <div id=time align="right" style=font-family:Verdana></div>
    <script>setInterval("time.innerHTML=‘今天是‘+new Date().toLocaleString()+‘ 星期‘+‘日一二三四五六‘.charAt(new Date().getDay())+‘ ‘;",1000);</script>
   
   
<script>
KISSY.ready(function(S){
    var path="http://10.125.1.58:88/img/";
    var href = location.href;
        /**
         * 调用系统默认浏览器打开链接 Apache httpd
         * http://127.0.0.1:88/report.html?run_stamp=20140302023811
         * &sec=250&min=4
         */

         
    var m, run_stamp;
    m = href.match(/stamp=(\d+)/);
    if(!m) run_stamp = "20140421122151";
    else run_stamp = m[1] ;
     
 
         
    var sec ;
    sec = href.match(/sec=(\d+)/);
    if(!sec) se = 0;
    else se=sec[1];
    
    
    var min;
    min = href.match(/min=(\d+)/);
    if(!min) mi=0;
    else mi = min[1];
   
    /* 请求报告资源接口,tomcat在8888端口监听 */
    S.use("node,io", function(S, Node, IO){
        IO({
            url: "http://10.125.1.58:8888/Report/go?run_stamp=" + run_stamp,
            dataType: "jsonp",
            jsonpCallback: "report",
            success: function(data) {
                var report=data;
                var runtime_log = path + run_stamp + "$runtime.log";
                var cpu_log     = path + run_stamp + "$cpu_usage.log";
               
                var bodyContent="<p><font face=\"verdana\">开始时间:" + run_stamp +"</font></p>";
                    bodyContent = bodyContent + "<p><font face=\"verdana\">运行时间: " + se + "s ( " + mi + " min ) </font></p>";
               
                    bodyContent = bodyContent + "<p align=center ><font face=\"verdana\"><a href=http://www.mamicode.com/""+runtime_log+"\">测试运行记录(点击查看)</a></font></p>";
                    bodyContent = bodyContent + "<p align=center ><font face=\"verdana\"><a href=http://www.mamicode.com/""+cpu_log +"\">CPU使用情况(点击查看)</a></font></p>";
                    bodyContent = bodyContent +  "<hr noshade size=5 align=center width=100% />";
                     bodyContent = bodyContent +  "<table style=\"table-layout:fixed\" border=\"0\">";
                /*表格总开始*/

                // 遍历DeviceID
                for (var i = 0; i < report.result.length; i++) {

                    bodyContent=bodyContent+"<tr><td width=\"80\" scope=\"col\"><font face=\"verdana\" >DeviceId(日志)</font></td>";
                    for (var j = 0; j < report.result[i].img_timestamp.length; j++) {
                        
                        bodyContent = bodyContent+"<td style=\"word-break : break-all\"; \"overflow:hidden\"; width=\"100\" scope=\"col\"><font face=\"verdana\" >"+report.result[i].url[j]+"</font></td>";
                        
                    }

                    bodyContent = bodyContent+"</tr>";
                        /*以上是urls行*/

                       /*这里是log记录*/
                    var log_url = path + run_stamp + "$" + report.result[i].device_id + "$runtime.log";
                    bodyContent = bodyContent+ "<tr><td scope=\"row\"><font face=\"verdana\" >"+report.result[i].device_id + "</font></td>";
                    //bodyContent = bodyContent+ "<tr><td scope=\"row\"><font face=\"verdana\" ><a href=http://www.mamicode.com/""+log_url+"\">"+report.result[i].device_id + "</a></font></td>";
                     /*下面是imgsrc行*/
                    for (var j = 0; j < report.result[i].img_timestamp.length; j++) {
                            var imgsrc_url = path + report.run_stamp+"$"+
                            report.result[i].device_id+"$"+
                            report.result[i].img_timestamp[j]+"$"+
                            report.result[i].img_name[j];
                           
                            bodyContent = bodyContent+ 
                            "<td><a href=http://www.mamicode.com/""+  imgsrc_url +"\"><img src=http://www.mamicode.com/"" +imgsrc_url+
                            "\" width=\"200\" height=\"300\"></td>";
                             
                    }
                    bodyContent = bodyContent+"</tr>";  
                };



                /********************************************************************************************************************/

                /*总表格结束*/

                bodyContent=bodyContent+"</table>";

                /*输出总的报告*/
                 
                    // document.write("<html><head><title>适配测试报告 " + report.run_stamp + "</title></head><body>" + bodyContent);
                //   document.write("</body></html>");
                S.one("body").append(bodyContent);

            }
        })
    });
});
</script>
</body>
</html>

报告url,img资源获取http接口:

  1. Request URL:
    http://10.73.72.122:8080/Report/go?_ksTS=1394101086006_19&callback=report&run_stamp=20140306052855
  2. Request Method:
    GET
  3. Status Code:
    200 OK
  4. Request Headersview source
    1. Accept:
      */*
    2. Accept-Encoding:
      gzip,deflate,sdch
    3. Accept-Language:
      zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4
    4. Connection:
      keep-alive
    5. Host:
      10.73.72.122:8080
    6. Referer:
      http://10.73.72.122:88/report.html?run_stamp=20140306052855&sec=336&min=5
    7. User-Agent:
      Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36
  5. Query String Parametersview sourceview URL encoded
    1. _ksTS:
      1394101086006_19
    2. callback:
      report
    3. run_stamp:
      20140306052855
  6. Response Headersview source
    1. Date:
      Thu, 06 Mar 2014 10:18:06 GMT
    2. Server:
      Apache-Coyote/1.1
    3. Transfer-Encoding:
      chunked


接口实现代码:

/**
 * Report.java ct.report Report 下午7:38:18 2014年2月28日 2014
 */
package ct.report;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import ct.dao.ReportDao;
/**
 * @author 东海陈光剑 2014年2月28日 下午7:38:18
 */
public class Report extends HttpServlet {
    /**
     * serialVersionUID long
     */
    private static final long serialVersionUID = -7282812094112943289L;
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        run_stamp = req.getParameter("run_stamp");
        callback = req.getParameter("callback");
        ReportDao dao = new ReportDao();
        Gson gson = new Gson();
        String json = gson.toJson(dao);
        // 在console上打印记录
        System.out.println(callback + "(" + json + ")");
        PrintWriter out = resp.getWriter();
        out.print(callback + "(" + json + ")");
        out.flush();
    }
    public String getRun_stamp() {
        return run_stamp;
    }
    public void setRun_stamp(String run_stamp) {
        Report.run_stamp = run_stamp;
    }
    static String run_stamp;
    static String callback;
}



/**
 * ReportDao.java ct.dao Report 下午9:32:16 2014年2月28日 2014
 */
package ct.dao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import ct.report.Report;
/**
 * @author 东海陈光剑 2014年2月28日 下午9:32:16
 */
public class ReportDao {
    // Report report = new Report();
    private String run_stamp = (new Report()).getRun_stamp();
    // private ArrayList<String> deviceList = (new Report()).getDeviceList();
    // private String device_id = (new Report()).getDevice_id();
    // QueryResult qr = new QueryResult();
    // Map<String, ArrayList<String>> result = (new QueryResult()).query(
    // run_stamp, device_id);
    List<HashMap<String, ArrayList<String>>> result = (new QueryResult())
            .query(run_stamp);
}



/**
 * QueryResult.java ct.dao Report 下午10:14:57 2014年2月28日 2014
 */
package ct.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author 东海陈光剑 2014年2月28日 下午10:14:57
 */
public class QueryResult {
    /**
     * @param args
     *            void main
     */
    public static void main(String[] args) {
        String run_stamp = "20140228041020";
        QueryResult qr = new QueryResult();
        // Map<String, ArrayList<String>> result = qr.query(run_stamp,
        // device_id);
        List<HashMap<String, ArrayList<String>>> result = qr.query(run_stamp);
        System.out.println(result);
    }
    List<HashMap<String, ArrayList<String>>> query(String run_stamp) {
        ArrayList<String> deviceList = getDeviceList(run_stamp);
        List<HashMap<String, ArrayList<String>>> result = new ArrayList<HashMap<String, ArrayList<String>>>();
        // Map<String, ArrayList<String>> imgName = new HashMap<String,
        // ArrayList<String>>();
        // Map<String, ArrayList<String>> imgTimeStamp = new HashMap<String,
        // ArrayList<String>>();
        try {
            Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序
            System.out.println("Success loading mysql driver!");
        } catch (Exception e) {
            System.out.print("Error loading mysql driver!");
            e.printStackTrace();
        }
        try {
            Connection connect = DriverManager.getConnection(
                    "jdbc:mysql://10.73.72.122:3306/test""root""isword");
            // 连接URL为 jdbc:mysql//服务器地址/数据库名 ,后面的2个参数分别是登陆用户名和密码
            System.out.println("Success connect mysql server!");
            Statement stmt = connect.createStatement();
            for (String device_id : deviceList) {
                String queryCmd = "SELECT * FROM ct_pic where run_stamp=‘"
                        + run_stamp + "‘ and device_id=‘" + device_id
                        + "‘ ORDER BY img_timestamp";
                System.out.println(queryCmd);
                ResultSet rs = stmt.executeQuery(queryCmd);
                ArrayList<String> urlList = new ArrayList<String>();
                ArrayList<String> imgNameList = new ArrayList<String>();
                ArrayList<String> imgTimeStampList = new ArrayList<String>();
                HashMap<String, ArrayList<String>> deviceMap = new HashMap<String, ArrayList<String>>();
                while (rs.next()) {
                    System.out.println(rs.getString("url"));
                    urlList.add(rs.getString("url"));
                    System.out.println(rs.getString("img_name"));
                    imgNameList.add(rs.getString("img_name"));
                    System.out.println(rs.getString("img_timestamp"));
                    imgTimeStampList.add(rs.getString("img_timestamp"));
                }
                ArrayList<String> d = new ArrayList<String>(1);
                d.add(device_id);
                deviceMap.put("device_id", d);
                deviceMap.put("url", urlList);
                deviceMap.put("img_name", imgNameList);
                deviceMap.put("img_timestamp", imgTimeStampList);
                result.add(deviceMap);
            }// end for
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Map<String, ArrayList<String>> result = new HashMap<String,
        // ArrayList<String>>();
        // result.put("device_list", deviceList);
        // result.put("url", urlList);
        // result.put("img_name", imgNameList);
        // result.put("img_timestamp", imgTimeStampList);
        return result;
    }
    Map<String, ArrayList<String>> query(String run_stamp, String device_id) {
        ArrayList<String> deviceList = getDeviceList(run_stamp);
        ArrayList<String> urlList = new ArrayList<String>();
        ArrayList<String> imgNameList = new ArrayList<String>();
        ArrayList<String> imgTimeStampList = new ArrayList<String>();
        try {
            Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序
            System.out.println("Success loading mysql driver!");
        } catch (Exception e) {
            System.out.print("Error loading mysql driver!");
            e.printStackTrace();
        }
        try {
            Connection connect = DriverManager.getConnection(
                    "jdbc:mysql://10.73.72.122:3306/test""root""isword");
            // 连接URL为 jdbc:mysql//服务器地址/数据库名 ,后面的2个参数分别是登陆用户名和密码
            System.out.println("Success connect mysql server!");
            Statement stmt = connect.createStatement();
            String queryCmd = "SELECT * FROM ct_pic where run_stamp=‘"
                    + run_stamp + "‘ and device_id=‘" + device_id
                    + "‘ ORDER BY img_timestamp";
            System.out.println(queryCmd);
            ResultSet rs = stmt.executeQuery(queryCmd);
            while (rs.next()) {
                System.out.println(rs.getString("img_name"));
                imgNameList.add(rs.getString("img_name"));
                System.out.println(rs.getString("url"));
                urlList.add(rs.getString("url"));
                System.out.println(rs.getString("img_timestamp"));
                imgTimeStampList.add(rs.getString("img_timestamp"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String, ArrayList<String>> result = new HashMap<String, ArrayList<String>>();
        result.put("device_list", deviceList);
        result.put("url", urlList);
        result.put("img_name", imgNameList);
        result.put("img_timestamp", imgTimeStampList);
        return result;
    }
    public ArrayList<String> getDeviceList(String run_stamp) {
        ArrayList<String> deviceList = new ArrayList<String>();
        try {
            Connection connect = DriverManager.getConnection(
                    "jdbc:mysql://10.73.72.122:3306/test""root""isword");
            // 连接URL为 jdbc:mysql//服务器地址/数据库名 ,后面的2个参数分别是登陆用户名和密码
            System.out.println("Success connect mysql server!");
            Statement stmt = connect.createStatement();
            String queryCmd = "SELECT device_id FROM ct_pic"
                    + " where run_stamp=‘" + run_stamp
                    + "‘ GROUP BY device_id;";
            System.out.println(queryCmd);
            ResultSet rs = stmt.executeQuery(queryCmd);
            while (rs.next()) {
                System.out.println(rs.getString("device_id"));
                deviceList.add(rs.getString("device_id"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return deviceList;
    }
}



测试xUnit代码:

package ct4taobaoh5.test;

import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import junit.framework.TestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.android.AndroidDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.events.WebDriverEventListener;

import ct4h5.Init;
import ct4h5.config.Const;
import ct4h5.util.EventListener;
import ct4h5.util.Util;

/**
 * 
 * @author 东海陈光剑 2014年2月21日 下午11:13:59
 */

@SuppressWarnings("deprecation")
@RunWith(Parameterized.class)
public class SearchTest extends TestCase {
    String deviceId;
    AndroidDriver driver;

    public SearchTest(String deviceId) {
        this.deviceId = deviceId;
    }

    @Before
    public void init() {
        /**
         * forward tcp
         */

        // Init.forward(deviceId);
        Init.init(deviceId);

    }

    /**
     * <p>
     * The custom runner <code>Parameterized</code> implements parameterized
     * tests. When running a parameterized test class, instances are created for
     * the cross-product of the test methods and the test data elements.
     * </p>
     * 
     * For example, to test a Fibonacci function, write:
     * 
     * <pre>
     * @RunWith(Parameterized.class)
     * public class FibonacciTest {
     *     @Parameters
     *     public static Collection<Object[]> data() {
     *         return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
     *                 { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
     *     }
     * 
     *     private int fInput;
     *     private int fExpected;
     * 
     *     public FibonacciTest(int input, int expected) {
     *         fInput = input;
     *         fExpected = expected;
     *     }
     * 
     *     @Test
     *     public void test() {
     *         assertEquals(fExpected, Fibonacci.compute(fInput));
     *     }
     * }
     * </pre>
     * 
     * <p>
     * Each instance of <code>FibonacciTest</code> will be constructed using the
     * two-argument constructor and the data values in the
     * <code>@Parameters</code> method.
     * </p>
     */


    @Parameterized.Parameters
    public static Collection deviceIds() {
        List<String> deviceList = Util.getDeviceList();
        List<String[]> col = new ArrayList<String[]>(); // List
        // [4d004077b4369049,
        // Coolpad5890-a1a1314a]
        // 把List<String> 转换成 List<String[]>
        for (String e : deviceList) {
            String[] el = new String[] { e };
            col.add(el);
        }
        return col; // 字符串数组 [[Ljava.lang.String;@b4e29b,
        // [Ljava.lang.String;@18941f7, null, null, null]
    }

    @Test
    public void testSearch() throws Exception {
        // String remote_driver_url = "http://localhost:5555/h5";
        // WebDriverEventListener eventListener = new EventListener();

        // WebDriver driver = new EventFiringWebDriver(new RemoteWebDriver(
        // new URL(remote_driver_url), DesiredCapabilities.android()))
        // .register(eventListener);
        /**
         * getDefaultUrl: return new URL("http://localhost:8080/wd/hub");
         */

        // driver = new AndroidDriver(new URL("http://localhost:" + port
        // + "/wd/hub"), DesiredCapabilities.android());
        driver = new AndroidDriver();
        /**
         * 首次打开“首页”
         */

        driver.get(Const.urlTaobaoOnline);// 线上
        // driver.get(Const.urlPre);//预发
        Thread.sleep(2000);
        Util.record(driver, deviceId);

        /**
         * 点击 搜索框
         */

        Util.click(driver, "//INPUT[@id=\"J_searchtext\"]");
        Util.record(driver, deviceId);

        /**
         * 在搜索框"//FORM/INPUT[1]"输入query keys
         */

        WebElement e = driver
                .findElementByXPath("//INPUT[@id=\"J_searchtext\"]");
        e.sendKeys("iphone5s");
        Util.record(driver, deviceId);// 搜索下拉推荐
        // e.submit();// 提交搜索
        e.sendKeys(Keys.ENTER);
        /**
         * 2s等待SRP加载渲染出来
         */

        Thread.sleep(2000);
        Util.record(driver, deviceId);

        /**
         * 点击“分类”
         */

        Util.click(driver, "//SPAN[@id=\"J_selt\"]");
        Thread.sleep(1000);
        Util.record(driver, deviceId);

        /**
         * 子类目可点击
         */

        Thread.sleep(1000);
        Util.click(driver, "//LI[1]/H2[1]");
        Util.record(driver, deviceId);

        // //////////////////////////////////////////////////////////////////////////////////

        /**
         * 打开“首页”
         */

        driver.get(Const.urlTaobaoOnline);// 线上
        // driver.get(Const.urlPre);//预发
        Thread.sleep(2000);
        Util.record(driver, deviceId);

        /**
         * 点击 搜索框
         */

        Util.click(driver, "//INPUT[@id=\"J_searchtext\"]");
        Util.record(driver, deviceId);

        /**
         * 在搜索框"//FORM/INPUT[1]"输入query keys
         */

        driver.findElementByXPath("//INPUT[@id=\"J_searchtext\"]").sendKeys(
                "iphone5s");
        Util.record(driver, deviceId);// 搜索下拉推荐
        // e.submit();// 提交搜索
        e.sendKeys(Keys.ENTER);
        /**
         * 2s等待SRP加载渲染出来
         */

        Thread.sleep(2000);
        Util.record(driver, deviceId);

        /**
         * 点击 筛选 //SPAN[@id="J_sift"]
         */

        Util.click(driver, "//SPAN[@id=\"J_sift\"]");
        Util.record(driver, deviceId);
        /**
         * 点击 筛选项目
         */

        Util.click(driver, "//LI[1]/LABEL[1]/INPUT[1]");
        Util.record(driver, deviceId);
        /**
         * 设定 “最高价”“最低价”
         */

        driver.findElementByXPath("//DIV[3]/DIV[1]/INPUT[1]").sendKeys("2000");
        driver.findElementByXPath("//DIV[2]/INPUT[1]").sendKeys("4000");

        /**
         * 点击“确定”
         */

        Util.click(driver, "//BUTTON[@id=\"J_siftSearchBtn\"]");
        Util.record(driver, deviceId);

        /**
         * 点击 销量 //DIV[4]/DIV[1]/UL[1]/LI[2]
         * 
         */

        Util.click(driver, "//DIV[4]/DIV[1]/UL[1]/LI[2]");
        Util.record(driver, deviceId);

        /**
         * 点击 价格排序: //DIV[4]/DIV[1]/UL[1]/LI[3]
         */

        Util.click(driver, "//DIV[4]/DIV[1]/UL[1]/LI[3]");
        Util.record(driver, deviceId);
        /**
         * 切大图://DIV[@id="tbh5v0"]/DIV[1]/DIV[4]/DIV[1]/DIV[1]/DIV[1]
         */

        Util.click(driver,
                "//DIV[@id=\"tbh5v0\"]/DIV[1]/DIV[4]/DIV[1]/DIV[1]/DIV[1]");
        Util.record(driver, deviceId);

        Util.click(driver,
                "//DIV[@id=\"tbh5v0\"]/DIV[1]/DIV[4]/DIV[1]/DIV[1]/DIV[1]");
        Util.record(driver, deviceId);

        Util.click(driver,
                "//DIV[@id=\"tbh5v0\"]/DIV[1]/DIV[4]/DIV[1]/DIV[1]/DIV[1]");
        Util.record(driver, deviceId);
    }

    @After
    public void destroy() {
        Init.destroy(deviceId);
        // driver.quit();
    }

}


package ct4taobaoh5.test;

import java.util.List;

import org.junit.runner.JUnitCore;
import org.junit.runner.notification.Failure;

import ct4h5.Install;
import ct4h5.Uninstall;
import ct4h5.config.Const;
import ct4h5.report.GenerateReport;
import ct4h5.util.Util;

/**
 * @author 东海陈光剑 2014年2月17日 下午8:58:02
 */

public class TestRunner {

    /**
     * @param args
     * @throws Exception
     */

    public static void main(String[] args) throws Exception {

        run();

    }

    /**
     * @throws Exception
     * 
     */

    private static void run() throws Exception {
        long start = System.currentTimeMillis();
        runTestCases();
        long end = System.currentTimeMillis();
        report(start, end);

    }

    private static void report(long start, long end) {
        System.out.println("Running Time: " + (end - start) / 1000 + " s"
                + "( " + (end - start) / 1000 / 60 + " min )");
        System.out.println("Run timestamp:" + Const.timestamp);

        String runningSec = (end - start) / 1000 + "";
        String runningMin = (end - start) / 1000 / 60 + "";
        // String startReportCmd = "start http://10.73.72.122:88/report.html";
        // Util.excuCmd(startReportCmd);
        GenerateReport.genReport(Const.timestamp, runningSec, runningMin);

    }

    /**
     * @throws Exception
     * 
     */

    private static void runTestCases() throws Exception {
        List<String> classList = Util
                .getClassInPackage(Const.packageTaobaoH5Path);
        for (String c : classList) {
            if (c.endsWith("Test")) {
                runClass(c);
            }
        }

    }

    public static void runClass(String className) throws Exception {

        String fullClassName = Const.packageTaobaoH5Path + "." + className;
        Class<?> c = Class.forName(fullClassName);

        long start = System.currentTimeMillis();

        for (Failure failure : JUnitCore.runClasses(c).getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(JUnitCore.runClasses(c).wasSuccessful());

        long end = System.currentTimeMillis();
        System.out.println(fullClassName + " | Running Time: " + (end - start)
                / 1000 + " s" + "( " + (end - start) / 1000 / 60 + " min )");
    }

    /**
     * 多线程执行安装android-server.apk
     */

    private static void install() {
        for (String e : Util.getDeviceList()) {
            (new Thread(new Install(e))).start();
        }

    }

    /**
     * 多线程执行安装android-server.apk
     */

    private static void uninstall() {
        for (String e : Util.getDeviceList()) {
            (new Thread(new Uninstall(e))).start();
        }

    }

}



基础应用类:

package ct4h5.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.android.AndroidDriver;
import org.openqa.selenium.remote.ScreenshotException;
import sun.misc.BASE64Decoder;
import com.taobao.sword.android.elements.IAndroidActivity;
import ct4h5.config.Const;
import ct4h5.dao.InsertDB;
import ct4h5.report.GenerateReport;
/**
 * @author 东海陈光剑 2014年2月22日 上午12:16:10
 */
public class Util {
    public static List<String> getDeviceList() {
        // TODO Auto-generated method stub
        Process process = null;
        String strBuff = "";
        String t = "";
        String command = "adb devices";
        try {
            process = Runtime.getRuntime().exec(command);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    process.getInputStream(), "utf-8"));
            while ((t = br.readLine()) != null) {
                strBuff += t + "\n";
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        /*
         * List of devices attached
         * \nCoolpad5890-a1a1314a\tdevice\nHC34WW907981\tdevice\n\n
         */
        print(strBuff);
        List<String> deviceList = new ArrayList<String>(5);
        String regex = "[\\n](.*)[\\t]";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(strBuff);
        while (matcher.find()) {
            String deviceId = strBuff.substring(matcher.start(), matcher.end());
            deviceId = deviceId.replaceAll("\\s*""");
            deviceList.add(deviceId);
        }
        return deviceList;
    }
    public static void print(String buff) {
        // TODO Auto-generated method stub
        System.out.println(buff);
    }
    /***********
     * 根据包名来获取此包下所有的类名及其实例
     * 
     * @param packagePath
     * @return
     */
    public static List<String> getClassInPackage(String packagePath) {
        List<String> classList = new ArrayList(5);
        String packageName = packagePath;
        String packageDirName = packageName.replace(".""/");
        Enumeration<URL> dirs = null;
        try {
            dirs = Thread.currentThread().getContextClassLoader()
                    .getResources(packageDirName);
            // 迭代此 Enumeration
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                File file = new File(url.getFile());
                // 把此目录下的所有文件列出
                String[] classes = file.list();
                // 循环此数组,并把.class去掉 ".class".length() = 6
                for (String className : classes) {
                    className = className.substring(0, className.length() - 6);
                    classList.add(className);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classList;
    }
    public static void record(AndroidDriver driver, String deviceId)
            throws InterruptedException {
        /**
         * 考虑到页面加载的时间,线程延时2s
         */
        Thread.sleep(2000);
        printTitle(driver, deviceId);
        // GenerateImage(driver, deviceId);
        screenShot(driver, deviceId);
    }
    /**
     * @param driver
     * @param deviceId
     */
    public static void printTitle(AndroidDriver driver, String deviceId) {
        System.out.println(deviceId + " | " + driver.getTitle());
        System.out.println(driver.getCurrentUrl());
    }
    public static void printTitle(AndroidDriver driver) {
        System.out.println(driver.getTitle());
        System.out.println(driver.getCurrentUrl());
    }
    /**
     * @param driver
     * @param xPath
     * @throws InterruptedException
     */
    public static void click(AndroidDriver driver, String xPath)
            throws InterruptedException {
        // int i = 0;
        // /**
        // * 最多等待5s
        // */
        // while (!driver.findElement(By.xpath(xPath)).isDisplayed() && i < 10)
        // {
        // Thread.sleep(500);
        // i++;
        // }
        // driver.getTouch().down(x, y);
        driver.findElement(By.xpath(xPath)).click();
        // driver.wait();// 报错:java.lang.IllegalMonitorStateException
        Thread.sleep(1000);
    }
    /**
     * 截图
     * 
     * @param driver
     * @param imgName
     */
    public void takeScreenShot(WebDriver driver, String imgName) {
        File scrFile = ((TakesScreenshot) driver)
                .getScreenshotAs(OutputType.FILE);
        try {
            FileUtils.copyFile(scrFile, new File("c:\\Learning\\" + imgName));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 发生异常截图
     * 
     * @param e
     * @return
     */
    public String extractScreenShot(WebDriverException e) {
        Throwable cause = e.getCause();
        if (cause instanceof ScreenshotException) {
            return ((ScreenshotException) cause).getBase64EncodedScreenshot();
        }
        return null;
    }
    /**
     * 将Base64转换成图片
     * 
     * @param activity
     * @param url
     * @return
     */
    /**
     * >adb -<deviceID> shell /system/bin/screencap -p /sdcard/screenshot.png
     * >adb -<deviceID> pull /sdcard/screenshot.png d:/screenshot.png 2990
     * KB/s (382785 bytes in 0.125s)
     * 
     * @param driver
     * @param deviceId
     * @return
     */
    public static boolean GenerateImage(AndroidDriver driver, String deviceId) {// 对字节数组字符串进行Base64解码并生成图片
        String url = driver.getCurrentUrl();
        System.out.println("AndroidDriver 截图 | " + url);
        String imgStr = driver.getScreenshotAs(OutputType.BASE64);
        /**
         * 这里记得加上"/"目录标示符
         */
        File fp = new File(Const.photoSavePath);
        if (!fp.isDirectory())
            fp.mkdirs();
        String imgPath = Const.photoSavePath + "/" + deviceId;
        File f = new File(imgPath);
        if (!f.isDirectory())
            f.mkdirs();
        if (!imgPath.endsWith("/"))
            imgPath += "/";
        String timeChamp = (new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"))
                .format(new Date());
        /**
         * url(去除非法字符)+时间戳 命名图片
         */
        String imgName = url.replaceAll("[\\/:*?\"<>|!#]""") + "_"
                + timeChamp + "_driver.jpeg";
        if (imgStr == null)
            // 图像数据为空
            return false;
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // Base64解码
            byte[] bytes = decoder.decodeBuffer(imgStr);
            for (int i = 0; i < bytes.length; ++i) {
                if (bytes[i] < 0) {// 调整异常数据
                    bytes[i] += 256;
                }
            }
            // 生成jpeg图片
            f = new File(imgPath);
            if (!f.isDirectory())
                f.mkdirs();
            if (!imgPath.endsWith("/"))
                imgPath += "/";
            String imgFullPathName = imgPath + imgName;
            OutputStream out = new FileOutputStream(imgFullPathName);
            out.write(bytes);
            out.flush();
            out.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    // @SuppressWarnings("deprecation")
    // public static boolean GenerateImage(AndroidDriver driver) {//
    // 对字节数组字符串进行Base64解码并生成图片
    //
    // String url = driver.getCurrentUrl();
    // System.out.println("截图 | " + url);
    // String imgStr = driver.getScreenshotAs(OutputType.BASE64);
    // String imgPath = Const.photoSavePath + "/";
    // String timeChamp = (new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"))
    // .format(new Date());
    // /**
    // * url(去除非法字符)+时间戳 命名图片
    // */
    // String imgName = url.replaceAll("[\\/:*?\"<>|]", "") + "-" + timeChamp
    // + ".jpeg";
    // if (imgStr == null)
    // // 图像数据为空
    // return false;
    // BASE64Decoder decoder = new BASE64Decoder();
    // try {
    // // Base64解码
    // byte[] bytes = decoder.decodeBuffer(imgStr);
    // for (int i = 0; i < bytes.length; ++i) {
    // if (bytes[i] < 0) {// 调整异常数据
    // bytes[i] += 256;
    // }
    // }
    // // 生成jpeg图片
    // File f = new File(imgPath);
    // if (!f.isDirectory())
    // f.mkdir();
    // if (!imgPath.endsWith("/"))
    // imgPath += "/";
    // String imgFullPathName = imgPath + imgName;
    // OutputStream out = new FileOutputStream(imgFullPathName);
    // out.write(bytes);
    // out.flush();
    // out.close();
    // return true;
    // } catch (Exception e) {
    // return false;
    // }
    // }
    @SuppressWarnings({ "restriction""unused" })
    public static boolean screenShot(AndroidDriver driver, String deviceId) {// 对字节数组字符串进行Base64解码并生成图片
        /**
         * 这里记得加上"/"目录标示符
         */
        File fp = new File(Const.photoSavePath);
        if (!fp.isDirectory())
            fp.mkdirs();
        String url = driver.getCurrentUrl();
        System.out.println("adb screenShot 截图 | " + url);
        // String imgStr = driver.getScreenshotAs(OutputType.BASE64);
        String imgPath = Const.photoSavePath + "/" + deviceId;
        File f = new File(imgPath);
        if (!f.isDirectory())
            f.mkdirs();
        if (!imgPath.endsWith("/"))
            imgPath += "/";
        String timeChamp = (new SimpleDateFormat("yyyyMMddhhmmss"))
                .format(new Date());
        /**
         * url(去除非法字符)+时间戳 命名图片
         */
        String imgName = url.replaceAll("[\\/:*?\"<>|!#]""") + "_"
                + timeChamp + ".jpeg";
        String imgFullPathName = imgPath + imgName;
        String imgSrcPath = Const.photoSrcPath + deviceId + "/" + imgName;
        InsertDB.insert(Const.timestamp, url, imgName, deviceId, timeChamp);
        //
        // /**
        // * 生成报告
        // */
        // StringBuffer reportUrl = GenerateReport.genReportUrl(driver,
        // deviceId,
        // imgSrcPath);
        // Const.report.append(reportUrl + "</tr>" + "<tr><th scope=\"row\">"
        // + deviceId + "</th>");
        // StringBuffer reportImgSrc = GenerateReport.genReportImgSrc(driver,
        // deviceId, imgSrcPath);
        // Const.report.append(reportImgSrc + "</tr>" + "</table>");
        /**
         * >adb -<deviceID> shell /system/bin/screencap -p
         * /sdcard/screenshot.png >adb -<deviceID> pull /sdcard/screenshot.png
         * d:/screenshot.png
         */
        String screencapCmd = "adb -s " + deviceId
                + " shell /system/bin/screencap -p  /sdcard/screenshot.png";
        String pullScreenShotCmd = "adb -s " + deviceId
                + " pull /sdcard/screenshot.png " + imgFullPathName;
        String rmScreenShotCmd = "rm -f /sdcard/screenshot.png";
        excuCmd(screencapCmd);
        excuCmd(pullScreenShotCmd);
        excuCmd(rmScreenShotCmd);
        return true;
        // Process process = null;
        // try {
        // process = Runtime.getRuntime().exec(screencapCmd);
        // BufferedReader br = new BufferedReader(new InputStreamReader(
        // process.getInputStream(), "utf-8"));
        // String buff = "";
        // String imgStr = "";
        // while ((buff = br.readLine()) != null) {
        // Util.print(buff);
        // imgStr += buff;
        // }
        //
        // if (imgStr == null) // 图像数据为空
        // return false;
        // BASE64Decoder decoder = new BASE64Decoder();
        //
        // // Base64解码
        // byte[] bytes = decoder.decodeBuffer(imgStr);
        // for (int i = 0; i < bytes.length; ++i) {
        // if (bytes[i] < 0) {// 调整异常数据
        // bytes[i] += 256;
        // }
        // }
        // // 生成jpeg图片
        // File f1 = new File(imgPath);
        // if (!f1.isDirectory())
        // f1.mkdir();
        // if (!imgPath.endsWith("/"))
        // imgPath += "/";
        // OutputStream out = new FileOutputStream(imgFullPathName);
        // out.write(bytes);
        // out.flush();
        // out.close();
        // return true;
        // } catch (Exception e) {
        // e.printStackTrace();
        // return false;
        // }
    }
    public static void excuCmd(String cmd) {
        System.out.println("$" + cmd);
        Process process = null;
        String buff = "";
        try {
            /**
             * adb -s HC34WW907981 install
             * D:/Android/test/taobao_android.sword.signed.apk
             */
            process = Runtime.getRuntime().exec(cmd);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    process.getInputStream(), "utf-8"));
            while ((buff = br.readLine()) != null) {
                Util.print(buff);
                // if (buff.contains("INSTALL_FAILED_ALREADY_EXISTS")) {
                // Util.print(devName + "已安装");
                // }
            }
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * @param e
     */
    public static void install(String deviceId) {
        String cmdInstall = "adb -s " + deviceId + " install -r "
                + Const.apkPath;
        Util.excuCmd(cmdInstall);
    }
}





Mobile webdriver android-server.apk配置:

package ct4h5;

import ct4h5.config.Const;
import ct4h5.util.Util;

/**
 * @author 东海陈光剑 2014年2月22日 上午2:27:35
 */

public class Init {

    /**
     * @param deviceId
     * 
     */

    public static void init(String deviceId) {
        String cmdUninstall = "adb -s " + deviceId
                + " uninstall org.openqa.selenium.android.app";
        String cmdInstall = "adb -s " + deviceId + " install -r "
                + Const.apkPath;

        /**
         * 启动WebDriver
         */

        int port = 8080;
        String cmdStart = "adb -s "
                + deviceId
                + " shell am start -a android.intent.action.MAIN -n org.openqa.selenium.android.app/.MainActivity -e debug true";
        String cmdForward = "adb -s " + deviceId + " forward tcp:" + port
                + " tcp:" + port;

         Util.excuCmd(cmdUninstall);
         Util.excuCmd(cmdInstall);
        Util.excuCmd(cmdStart);
        Util.excuCmd(cmdForward);

    }

    /**
     * @param deviceId
     * 
     */

    public static void forward(String deviceId) {

        int port = 8080;
        String cmdStart = "adb -s "
                + deviceId
                + " shell am start -a android.intent.action.MAIN -n org.openqa.selenium.android.app/.MainActivity -e debug true";
        String cmdForward = "adb -s " + deviceId + " forward tcp:" + port
                + " tcp:" + port;
        Util.excuCmd(cmdStart);
        Util.excuCmd(cmdForward);

    }

    public static void destroy(String deviceId) {
        String cmdUninstall = "adb -s " + deviceId
                + " uninstall org.openqa.selenium.android.app";

        Util.excuCmd(cmdUninstall);

    }

}



写数据库:

package ct4h5.dao;

import java.sql.*;

import org.testng.internal.remote.SlavePool;

public class InsertDB {

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++)
            insert("2", "2", "2", "2", "2");
    }

    public static boolean insert(String timestamp, String url, String imgName,
            String deviceId, String imgTimeChamp) {
        try {
            Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序
            System.out.println("Success loading Mysql Driver!");
        } catch (Exception e) {
            System.out.print("Error loading Mysql Driver!");
            e.printStackTrace();
        }
        try {
            Connection connect = DriverManager.getConnection(
                    "jdbc:mysql://10.73.72.122:3306/test", "root", "isword");
            // 连接URL为 jdbc:mysql//服务器地址/数据库名 ,后面的2个参数分别是登陆用户名和密码

            System.out.println("Success connect Mysql server!");
            Statement stmt = connect.createStatement();
            // String insertCmd = "insert into ct_pic  values(" + "\‘" +
            // timestamp
            // + "\‘" + "," + "\‘" + deviceId + "\‘" + "," + "\‘"
            // + imgName + "\‘" + "," + "\‘" + url + "\‘" + ")";
            String insertCmd = "INSERT INTO ct_pic(run_stamp,device_id,img_name,url,img_timestamp)"
                    + " VALUES ("
                    + "‘"
                    + timestamp
                    + "‘,"
                    + "‘"
                    + deviceId
                    + "‘,"
                    + "‘"
                    + imgName
                    + "‘,"
                    + "‘"
                    + url
                    + "‘,‘"
                    + imgTimeChamp + "‘)";
            System.out.println(insertCmd);
            boolean rs = stmt.execute(insertCmd);
            return rs;
            // while (rs.next()) {
            // System.out.println(rs.getString("img_name"));
            // }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

// GRANT ALL ON *.* TO root@"%" IDENTIFIED BY isword;








来自为知笔记(Wiz)