51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 1977|回复: 1
打印 上一主题 下一主题

[资料] 代码解放双手,一次自动化实践

[复制链接]
  • TA的每日心情
    无聊
    7 小时前
  • 签到天数: 935 天

    连续签到: 2 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2020-7-9 16:45:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    因为要反复测试一个接口,手工慢慢执行效率太低,就打算自动化实现。下面记录一下整个实现的过程和遇到的问题。
      因为开发同事有提供一个调用接口的项目和main测试方法,很自然的我就想到了要把这个方法改成用junit来实现。如果单纯一个@Test方法,那么和直接执行main方法差别不大,幸好junit提供了参数化的实现。我参考网上搜索的资料之后,实现了简单的参数化,具体代码如下:
    @RunWith(value=Parameterized.class)

      public class TestTransationClient {

      DictionUtil du;

      TransactionClient tc;

      String url = "https://接口地址";

      private String row;

      private String authentType;

      private String merNo;

      private String IdNo;

      private String name;

      private String mobileNo;

      private String bankCardNo;

      public TestTransationClient(String row,String authentType,String merNo,String IdNo,String name,String mobileNo,String bankCardNo) {

      // 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;

      }

      @Parameters(name="名字")

      public static Iterable<Object[]> data(){

      return Arrays.asList(new Object[][]{

      {"11","123456","","roy","13312345678",""},

      {"12","123456","123456","李白","13800138000","62213466552222222"},

      {"21","123456","","roy","",""},

      {"21","123456","","","",""}

      });

      }

      @Test方法会读取

      return Arrays.asList(new Object[][]{

      {"11","123456","","roy","13312345678",""},

      {"12","123456","","","",""},

      {"21","123456","","roy","",""},

      {"21","123456","","","",""}

      });

    里面的数据,每次执行读取一行,算作一条测试用例。列表存在几行数据就执行了几条测试用例,现在已经比之前每执行一条测试用例就要改一次数据方便了些。但是这样还是不够智能,我决定让他直接读取excel里面的数据,然后将运行结果写入到excel测试结果列。
      Excel的读写不难,我用的是jxl包。读excel 的方法如下
    1. /**

    2.   * 读取测试用例第4列参数

    3.   * 参数格式为:认证类型|商户号|身份证号|姓名|手机号|银行卡号|code|codeno|value

    4.   * 例子:11|123456|123456|roy||||1|1

    5.   * @param ExcelLocation 测试用例存放路径

    6.   * [url=home.php?mod=space&uid=26358]@return[/url] 返回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);

    26.   list.add(temp);

    27.   int row=i+1;

    28.   System.out.println("将第"+row+"行数据添加到list成功");

    29.   //                    for (int j = 0; j < temp.length; j++) {

    30.   //                        System.out.println(temp[j]);

    31.   //                    }

    32.   }

    33.   }

    34.   } catch (Exception e) {

    35.   // TODO Auto-generated catch block

    36.   e.printStackTrace();

    37.   }

    38.   return list;

    39.   }
    复制代码
         我将测试参数用“|”隔开,每个位置一个参数,读出单元格的数据后,用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在后台页面上改。代码如下:
    1. public void editDiction(String code, String codeno, String value) throws InterruptedException {

    2.   login("账号","密码");

    3.   driver.switchTo().frame(1).findElement(By.linkText("数据字典管理")).click();

    4.   System.out.println("进入数据字典菜单,开始修改数据字典");

    5.   driver.switchTo().defaultContent();

    6.   driver.switchTo().frame(driver.findElement(By.xpath("//frame[@src=\"popedom/manage.jsp\"]"))).findElement(By.id("code")).clear();

    7.   driver.findElement(By.id("code")).sendKeys(code);

    8.   driver.findElement(By.cssSelector("input[type=\"image\"]")).click();

    9.   // driver.findElement(By.id("edit_2058595")).click();

    10.   driver.findElement(By.xpath("//*[@alt=\"修改\"]")).click();

    11.   driver.findElement(By.cssSelector("Input[id^=\"codeNo_\"]")).clear();

    12.   driver.findElement(By.cssSelector("Input[id^=\"codeNo_\"]")).sendKeys(codeno);

    13.   // Thread.sleep(11111);

    14.   // driver.findElement(By.id("codeNo_2058595")).clear();

    15.   // driver.findElement(By.id("codeNo_2058595")).sendKeys(codeno);

    16.   driver.findElement(By.cssSelector("Input[id^=\"value_\"]")).clear();

    17.   driver.findElement(By.cssSelector("Input[id^=\"value_\"]")).sendKeys(value);

    18.   // driver.findElement(By.id("value_2058595")).clear();

    19.   // driver.findElement(By.id("value_2058595")).sendKeys(value);

    20.   driver.findElement(By.xpath("//img[@alt=\"保存\"]")).click();

    21.   System.out.println("修改数据字典成功:" + code);

    22.   driver.quit();

    23.   }
    复制代码


    实现过程中遇到两个问题,第一,我直接执行IDE录制(IDE真是个好东西)的脚本不成功,定位不到元素。原来页面使用了frame,参考网上资料后,完美解决问题。只要加一句driver.switchTo().frame(1)切换frame后就能定位到了。

      第二,是元素ID是会变化的,类似于这种value_1、value_2,就是同一个输入框,列表不同行的ID是不一样的,为了能够复用代码,在网上找到了使用findElement(By.cssSelector("Input[id^=\"value_\"]"))的方法完美解决。

      "Input[id^=\"value_\"表示,id的头为value_的input元素。类似的,我又写了个新增数据字典的方法
    1. public void addDiction(String code, String codeno, String value) throws Exception{

    2.   login("账号","密码");

    3.   driver.switchTo().frame(1).findElement(By.linkText("数据字典管理")).click();

    4.   // ERROR: Caught exception [ERROR: Unsupported command [selectWindow | name=main | ]]

    5.   driver.switchTo().defaultContent();

    6.   driver.switchTo().frame(driver.findElement(By.xpath("//frame[@src=\"popedom/manage.jsp\"]"))).findElement(By.id("code")).clear();

    7.   driver.findElement(By.xpath("(//input[@type='image'])[2]")).click();

    8.   System.out.println("开始新增数据字典");

    9.   //            Thread.sleep(5000);

    10.   driver.findElement(By.id("code")).clear();

    11.   driver.findElement(By.id("code")).sendKeys(code);

    12.   driver.findElement(By.id("value")).clear();

    13.   driver.findElement(By.id("value")).sendKeys(codeno);

    14.   driver.findElement(By.id("codeNo")).clear();

    15.   driver.findElement(By.id("codeNo")).sendKeys(value);

    16.   driver.findElement(By.cssSelector("input[type=\"image\"]")).click();

    17.   //            Thread.sleep(5000);

    18.   System.out.println("新增数据字典成功:"+ code);

    19.   driver.quit();

    20.   }

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

    22.   public void login(String account,String password){

    23.   System.setProperty("webdriver.firefox.bin", "D:\\Program Files (x86)\\Mozilla Firefox\\24.0\\firefox.exe");

    24.   driver = new FirefoxDriver();

    25.   baseUrl = "后台地址";

    26.   driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

    27.   driver.get(baseUrl + "/user/login.jsp");

    28.   // driver.manage().window().maximize();

    29.   driver.findElement(By.id("userName")).click();

    30.   driver.findElement(By.id("userName")).clear();

    31.   driver.findElement(By.id("userName")).sendKeys(account);

    32.   driver.findElement(By.id("UserPwd")).click();

    33.   driver.findElement(By.id("UserPwd")).clear();

    34.   driver.findElement(By.id("UserPwd")).sendKeys(password);

    35.   driver.findElement(By.cssSelector("input[type=\"image\"]")).click();

    36.   }
    复制代码

    最后再遍历数据库数据字典表,遍历参数与要操作的参数做对比,参数存在则调用修改参数的方法,数据不存在则调用新增参数的方法。在使用JDBC的过程中,一开始报了DB2 SQL Error: SQLCODE=-204, SQLSTATE=42704, SQLERRMC=表名,原来是因为定位不到schema,增加?properties.setProperty("currentSchema","用户Schema");就可以了。代码如下
    1. public boolean dictionIsExist(String code){

    2.   Connection conn = null;

    3.   Statement stmt = null;

    4.   ResultSet rs = null;

    5.   boolean exist = false;

    6.   try {

    7.   Properties properties = new Properties();

    8.   properties.setProperty("user","登录名");

    9.   properties.setProperty("password","密码");

    10.   properties.setProperty("currentSchema","用户Schema");

    11.   Class.forName("com.ibm.db2.jcc.DB2Driver");

    12.   conn=DriverManager.getConnection("jdbc:db2://数据库链接", properties);

    13.   stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);//ResultSet.TYPE_SCROLL_SENSITIVE类型的ResultSet才能使用rs.isLast()

    14.   String sql="select * from dna_diction"; stmt.executeQuery(sql); rs=stmt.getResultSet();

    15.   int g=0; while(rs.next()){

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

    17.   if (dbCode!=null&&code.equals(dbCode)){

    18.   exist=true;

    19.   System.out.println("数据字典已存在,调用修改数据字典的方法");

    20.   break; }

    21.   if (rs.isLast()){

    22.   System.out.println("数据字典不存在,调用新增数据字典的方法");

    23.   exist=false;

    24.   break; } }

    25.   rs.close();

    26.   stmt.close();

    27.   conn.close(); }

    28.   catch (Exception e) {

    29.   e.printStackTrace(); }

    30.   return exist; } }


    31.   最后的@Test方法如下



    32.    import java.util.Date;import java.util.List;

    33.   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;

    34.   @RunWith(value=Parameterized.class)public class TestTransationClient {

    35.   DictionUtil du;

    36.   TransactionClient tc;

    37.   String url = "接口api地址";

    38.   private String row;

    39.   private String authentType;

    40.   private String merNo;

    41.   private String IdNo;

    42.   private String name;

    43.   private String mobileNo;

    44.   private String bankCardNo;

    45.   private String code;

    46.   private String codeno;

    47.   private String value;

    48.   public TestTransationClient(String row,String authentType,String merNo,String IdNo,String name,String mobileNo,String bankCardNo,String code,String codeno,String value) {

    49.   // TODO Auto-generated constructor stub

    50.   this.row=row;

    51.   this.authentType=authentType;

    52.   this.merNo=merNo;

    53.   this.IdNo=IdNo;

    54.   this.name=name;

    55.   this.mobileNo=mobileNo;

    56.   this.bankCardNo=bankCardNo;

    57.   this.code=code;

    58.   this.codeno=codeno;

    59.   this.value=value;

    60.   }

    61.   @Parameters(name="名字{0}****")

    62.   public static Iterable<Object[]> data(){

    63.   List list = null;

    64.   list=new ExcelUtil().readExcel("E:\\test\\AS.xls");

    65.   return list;

    66.   }

    67.   @Before

    68.   public void setUp() throws Exception {

    69.   }

    70.   @After

    71.   public void tearDown() throws Exception {

    72.   }

    73.   @Test

    74.   public void test() throws Exception {

    75.   tc=new TransactionClient(url);

    76.   tc.setServerCert(Toolkit.getPropertyFromFile();

    77.   String encryptKey = Toolkit.random(24);

    78.   tc.setMerchantNo(merNo);

    79.   tc.setMerchantPwd("123456"); //        tc.setTerminalNo("123456");//        String transactType = authentType;//        String address = "";////        String accountno = bankCardNo;////         String idcardno=bankCardNo;//        String name = name;// //        String mobile = mobileNo;

    80.   du=new DictionUtil();

    81.   if(du.dictionIsExist(code)){

    82.   du.editDiction(code,codeno,value);

    83.   }else{

    84.   du.addDiction(code, codeno, value);

    85.   }

    86.   AuthentXmlImpl result=tc.a(Toolkit.yyyyMMddHHmmssSSS(new Date()), encryptKey, authentType, address, bankCardNo, IdNo, name, mobileNo);

    87.   int rowIndex=Integer.valueOf(row)-1;

    88.   new ExcelUtil().writeExcel(result.toString(),7,rowIndex,"E:\\test\\AS.xls");

    89.   if (authentType.equals("11")){

    90.   Assert.assertEquals("0000",result.getIDCardNameResult());

    91.   }else if(authentType.equals("12")){

    92.   Assert.assertTrue(result.getIDCardNameResult().equals("0000"));

    93.   }else if(authentType.equals("21")){

    94.   Assert.assertEquals("0000", result.getIDCardNoResult());

    95.   }

    96.   }

    97.   }


    复制代码


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

      代码已去掉一些敏感信息,不便之处,敬请谅解。
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-4-23 16:19 , Processed in 0.067487 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表