zoukankan      html  css  js  c++  java
  • 记我的第一次自动化尝试

    因为要反复测试一个接口,手工慢慢执行效率太低,就打算自动化实现。下面记录一下整个实现的过程和遇到的问题。

    因为开发同事有提供一个调用接口的测试方法,很自然的我就想到了要把这个方法改成用junit来实现。如果单纯一个@Test方法,那么和直接执行main方法差别不大,幸好junit提供了参数化的实现。我参考http://blog.csdn.net/zen99t/article/details/50572373之后,实现了简单的参数化,具体代码如下:

     1 @RunWith(value=Parameterized.class)
     2 public class TestTransationClient {
     3     DictionUtil du;
     4     TransactionClient tc;
     5     String url = "https://接口地址";
     6     private String row;
     7     private String authentType;
     8     private String merNo;
     9     private String IdNo;
    10     private String name;
    11     private String mobileNo;
    12     private String bankCardNo;
    13    16     public TestTransationClient(String row,String authentType,String merNo,String IdNo,String name,String mobileNo,String bankCardNo) {
    17         // TODO Auto-generated constructor stub
    18         this.row=row;
    19         this.authentType=authentType;
    20         this.merNo=merNo;
    21         this.IdNo=IdNo;
    22         this.name=name;
    23         this.mobileNo=mobileNo;
    24         this.bankCardNo=bankCardNo;
    25     }
    26     @Parameters(name="名字")
    27     public static Iterable<Object[]> data(){
    28        return Arrays.asList(new Object[][]{
    29            {"11","123456","","roy","13312345678",""},
    30             {"12","123456","123456","李白","13800138000","62213466552222222"},
    31            {"21","123456","","roy","",""},
    32             {"21","123456","","","",""}
    33         });
    34     }

    @Test方法会读取

    return Arrays.asList(new Object[][]{
    29            {"11","123456","","roy","13312345678",""},
    30             {"12","123456","","","",""},
    31            {"21","123456","","roy","",""},
    32             {"21","123456","","","",""}
    33         });
    里面的数据,每次执行读取一行,算作一条测试用例。列表存在几行数据就执行了几条测试用例,现在已经比之前每执行一条测试用例就要改一次数据方便了些。但是这样还是不够智能,我决定让他直接读取excel里面的数据,然后将运行结果写入到excel测试结果列。
    Excel的读写不难,我用的是jxl包。读excel 的方法如下
     1 /**
     2      * 读取测试用例第4列参数
     3      * 参数格式为:认证类型|商户号|身份证号|姓名|手机号|银行卡号|code|codeno|value  
     4      * 例子:11|123456|123456|roy||||1|1
     5      * @param ExcelLocation 测试用例存放路径
     6      * @return 返回Junit参数化所需要的list
     7      */
     8     @SuppressWarnings("unchecked")
     9     public List readExcel(String ExcelLocation) {
    10         jxl.Workbook readWorkBook = null;
    11         String[] temp;
    12         List list = new ArrayList<String[]>();
    13         String oraginalData = null;
    14         int k = 0;
    15         try {
    16             InputStream input = new FileInputStream(ExcelLocation);
    17             readWorkBook = Workbook.getWorkbook(input);
    18             Sheet readSheet = readWorkBook.getSheet(1);
    19             for (int i = 0; i < readSheet.getRows(); i++) {
    20                 Cell cellInput = readSheet.getCell(4, i);
    21                 Cell dataSwitch=readSheet.getCell(3, i); //设置了控制是否执行案例的开关,填enable则执行
    22                 if (cellInput.getContents().contains("|")&&dataSwitch.getContents().equals("enable")) {
    23                     oraginalData = cellInput.getContents();
    24                     // System.out.println(oraginalData);
    25                     temp = oraginalData.split("\|", 10); 
    list.add(temp);
    26 int row=i+1; 27 System.out.println("将第"+row+"行数据添加到list成功"); 28 // for (int j = 0; j < temp.length; j++) { 29 // System.out.println(temp[j]); 30 // } 31 } 32 33 } 34 35 } catch (Exception e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } 39 return list; 40 }

    我将测试参数用“|”隔开,每个位置一个参数,读出单元格的数据后,用split方法将一串字符分割存到数组,然后再把数组存到list里面,作为junit执行需要的参数,每个数组作为一条测试用例的输入数据。

    写入Excel的方法如下:

     1 /**
     2      * 往excel写数据
     3      * @param data 需要写入的字符串
     4      * @param column 目标单元格列号
     5      * @param row     目标单元格行号
     6      * @param ExcelName  文件路径
     7      */
     8     public void writeExcel(String data,int column,int row,String ExcelName) {
     9         try {
    10             InputStream input = new FileInputStream(ExcelName);
    11             Workbook readWorkBook = Workbook.getWorkbook(input);
    12             Sheet readSheet = readWorkBook.getSheet(1);
    13             WritableWorkbook wwb = Workbook.createWorkbook(new File(ExcelName), readWorkBook);
    14             WritableSheet ws = wwb.getSheet(1);
    15             Label label = new Label(column,row, data);
    16             ws.addCell(label);
    17             int ji=row+1;
    18             System.out.println("填充第"+ji+"行表格成功");            
    19             wwb.write();
    20             System.out.println("写入表格并保存成功");
    21             wwb.close();
    22         } catch (Exception e) {
    23             // TODO Auto-generated catch block
    24             e.printStackTrace();
    25         } 
    26     }

    写这里我遇到了一个问题,就是一开始我是读取输入的文件A后重新创建一个新的文件B作为写的对象文件,每次创建的时候会把A所有的内容复制到B然后再写,这样的话导致了我执行下一条案例时也要重新创建B,那么上一条案例写入的执行结果就会丢失。解决办法是,把所有文件的命名改成一致,就是输入文件A,写完后的文件也命名为A,那么就会覆盖原来的输入文件作为新的输入文件,继续被下一条案例读取,就不会丢失之前的执行结果了。

    做到这里,我已经能够实现自动读写和执行方法调用接口了,但是还漏了一步,就是执行前可能要配置数据字典。我想过找开发要一份这个功能的代码,但是考虑到方法依赖太多,太过复杂。师姐建议我用selenium在后台页面上改。代码如下:

    public void editDiction(String code, String codeno, String value) throws InterruptedException {

    login("账号","密码");
    driver.switchTo().frame(1).findElement(By.linkText("数据字典管理")).click();
    System.out.println("进入数据字典菜单,开始修改数据字典");
    driver.switchTo().defaultContent();
    driver.switchTo().frame(driver.findElement(By.xpath("//frame[@src="popedom/manage.jsp"]"))).findElement(By.id("code")).clear();
    driver.findElement(By.id("code")).sendKeys(code);
    driver.findElement(By.cssSelector("input[type="image"]")).click();

    // driver.findElement(By.id("edit_2058595")).click();
    driver.findElement(By.xpath("//*[@alt="修改"]")).click();
    driver.findElement(By.cssSelector("Input[id^="codeNo_"]")).clear();
    driver.findElement(By.cssSelector("Input[id^="codeNo_"]")).sendKeys(codeno);
    // Thread.sleep(11111);
    // driver.findElement(By.id("codeNo_2058595")).clear();
    // driver.findElement(By.id("codeNo_2058595")).sendKeys(codeno);
    driver.findElement(By.cssSelector("Input[id^="value_"]")).clear();
    driver.findElement(By.cssSelector("Input[id^="value_"]")).sendKeys(value);
    // driver.findElement(By.id("value_2058595")).clear();
    // driver.findElement(By.id("value_2058595")).sendKeys(value);
    driver.findElement(By.xpath("//img[@alt="保存"]")).click();
    System.out.println("修改数据字典成功:" + code);
    driver.quit();
    }

    实现过程中遇到两个问题,第一,我直接执行IDE录制(IDE真是个好东西)的脚本不成功,定位不到元素。原来页面使用了frame,参考http://blog.csdn.net/lykangjia/article/details/46348535后,完美解决问题。只要加一句

    driver.switchTo().frame(1)切换frame后就能定位到了。第二,是元素ID是会变化的,类似于这种a_1、a_2,就是同一个输入框,列表不同行的ID是不一样的,为了能够复用代码,在网上找到了使用findElement(By.cssSelector("Input[id^="value_"]"))的方法完美解决。
    "Input[id^="value_"表示,id的头为value_的input元素。详见https://www.cnblogs.com/sylvia-liu/p/4469597.html
    类似的,我又写了个新增数据字典的方法
    public void addDiction(String code, String codeno, String value) throws Exception{
                login("账号","密码");
                driver.switchTo().frame(1).findElement(By.linkText("数据字典管理")).click();
                // ERROR: Caught exception [ERROR: Unsupported command [selectWindow | name=main | ]]
                driver.switchTo().defaultContent();
                driver.switchTo().frame(driver.findElement(By.xpath("//frame[@src="popedom/manage.jsp"]"))).findElement(By.id("code")).clear();
                driver.findElement(By.xpath("(//input[@type='image'])[2]")).click();
                System.out.println("开始新增数据字典");
    //            Thread.sleep(5000);
                driver.findElement(By.id("code")).clear();
                driver.findElement(By.id("code")).sendKeys(code);
                driver.findElement(By.id("value")).clear();
                driver.findElement(By.id("value")).sendKeys(codeno);
                driver.findElement(By.id("codeNo")).clear();
                driver.findElement(By.id("codeNo")).sendKeys(value);
                driver.findElement(By.cssSelector("input[type="image"]")).click();
    //            Thread.sleep(5000);
                System.out.println("新增数据字典成功:"+ code);
                driver.quit();
        }

    login方法,调起火狐并登录系统

    public void login(String account,String password){
            System.setProperty("webdriver.firefox.bin", "D:\Program Files (x86)\Mozilla Firefox\24.0\firefox.exe");
            driver = new FirefoxDriver();
            baseUrl = "后台地址";
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            driver.get(baseUrl + "/user/login.jsp");
            // driver.manage().window().maximize();
            driver.findElement(By.id("userName")).click();
            driver.findElement(By.id("userName")).clear();
            driver.findElement(By.id("userName")).sendKeys(account);
            driver.findElement(By.id("UserPwd")).click();
            driver.findElement(By.id("UserPwd")).clear();
            driver.findElement(By.id("UserPwd")).sendKeys(password);
            driver.findElement(By.cssSelector("input[type="image"]")).click();
        }

    最后再遍历数据库数据字典表,遍历参数与要操作的参数做对比,参数存在则调用修改参数的方法,数据不存在则调用新增参数的方法。在使用JDBC的过程中,一开始报了DB2 SQL Error: SQLCODE=-204, SQLSTATE=42704, SQLERRMC=表名,原来是因为定位不到schema,增加 properties.setProperty("currentSchema","用户Schema");就可以了。参考链接http://bbs.csdn.net/topics/320197969

    代码如下

    public boolean dictionIsExist(String code){
             Connection conn = null;
              Statement stmt = null;
              ResultSet rs = null;
              boolean exist = false;
              try {                          
                    Properties properties = new Properties();
                    properties.setProperty("user","登录名");
                    properties.setProperty("password","密码");
                    properties.setProperty("currentSchema","用户Schema");
                    Class.forName("com.ibm.db2.jcc.DB2Driver");
                    conn=DriverManager.getConnection("jdbc:db2://数据库链接", properties);
                    stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);//ResultSet.TYPE_SCROLL_SENSITIVE类型的ResultSet才能使用rs.isLast()
                   String sql="select * from dna_diction"; stmt.executeQuery(sql); rs=stmt.getResultSet();
    int g=0; while(rs.next()){

    String dbCode
    =rs.getString("code");

    if (dbCode!=null&&code.equals(dbCode)){
    exist
    =true;
    System.out.println(
    "数据字典已存在,调用修改数据字典的方法");
    break; }

    if (rs.isLast()){
    System.out.println(
    "数据字典不存在,调用新增数据字典的方法");
    exist
    =false;
    break; } }
    rs.close();
    stmt.close();
    conn.close(); }
    catch (Exception e) {

    e.printStackTrace(); }

    return exist; } }

    最后的@Test方法如下

    import java.util.Date;
    import java.util.List;
    
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;
    
    
    
    @RunWith(value=Parameterized.class)
    public class TestTransationClient {
        DictionUtil du;
        TransactionClient tc;
        String url = "接口api地址";
        private String row;
        private String authentType;
        private String merNo;
        private String IdNo;
        private String name;
        private String mobileNo;
        private String bankCardNo;
        private String code;
        private String codeno;
        private String value;
        public TestTransationClient(String row,String authentType,String merNo,String IdNo,String name,String mobileNo,String bankCardNo,String code,String codeno,String value) {
            // TODO Auto-generated constructor stub
            this.row=row;
            this.authentType=authentType;
            this.merNo=merNo;
            this.IdNo=IdNo;
            this.name=name;
            this.mobileNo=mobileNo;
            this.bankCardNo=bankCardNo;
            this.code=code;
            this.codeno=codeno;
            this.value=value;
        }
        @Parameters(name="名字{0}****")
        public static Iterable<Object[]> data(){
            List list = null;
            list=new ExcelUtil().readExcel("E:\test\AS.xls");
            return list;
        }
        @Before
        public void setUp() throws Exception {
            
            
        }
    
        @After
        public void tearDown() throws Exception {
        }
    
        @Test
        public void test() throws Exception {
            tc=new TransactionClient(url);    
            tc.setServerCert(Toolkit.getPropertyFromFile();
            String encryptKey = Toolkit.random(24);
            tc.setMerchantNo(merNo); 
            tc.setMerchantPwd("123456"); //
            tc.setTerminalNo("02028828");
    //        String transactType = authentType;//
            String address = "";//
    //        String accountno = bankCardNo;//
    //         String idcardno=bankCardNo;
    //        String name = name;// 
    //        String mobile = mobileNo;
            du=new DictionUtil();
            if(du.dictionIsExist(code)){
                du.editDiction(code,codeno,value);
            }else{
                du.addDiction(code, codeno, value);
            }
        
            
            
            AuthentXmlImpl result=tc.a(Toolkit.yyyyMMddHHmmssSSS(new Date()), encryptKey, authentType, address, bankCardNo, IdNo, name, mobileNo);
            int rowIndex=Integer.valueOf(row)-1;
            new ExcelUtil().writeExcel(result.toString(),7,rowIndex,"E:\test\AS.xls");
            if (authentType.equals("11")){
            Assert.assertEquals("0000",result.getIDCardNameResult());
            }else if(authentType.equals("12")){
                Assert.assertTrue(result.getIDCardNameResult().equals("0000"));
            }else if(authentType.equals("21")){
                Assert.assertEquals("0000", result.getIDCardNoResult());
                }
        }
    
    }

    至此,第一次自动化尝试成功,以后测试会方便很多,还可以根据需要再做调整,增加输入参数扩展都很方便。在此再次谢谢广大肯分享自己的心得体会和问题解决方案的网友们,特别感谢上述参考链接的作者们,谢谢。

    代码已去掉一些敏感信息,不便之处,敬请谅解。

    
    



  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/fpzh/p/7872869.html
Copyright © 2011-2022 走看看