代码解放双手,一次自动化实践

发表于:2020-7-06 10:02

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:NoKnow    来源:51Testing软件测试网原创

   因为要反复测试一个接口,手工慢慢执行效率太低,就打算自动化实现。下面记录一下整个实现的过程和遇到的问题。
  因为开发同事有提供一个调用接口的项目和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 的方法如下
   /**
  * 读取测试用例第4列参数
  * 参数格式为:认证类型|商户号|身份证号|姓名|手机号|银行卡号|code|codeno|value
  * 例子:11|123456|123456|roy||||1|1
  * @param ExcelLocation 测试用例存放路径
  * @return 返回Junit参数化所需要的list
  */
  @SuppressWarnings("unchecked")
  public List readExcel(String ExcelLocation) {
  jxl.Workbook readWorkBook = null;
  String[] temp;
  List list = new ArrayList<String[]>();
  String oraginalData = null;
  int k = 0;
  try {
  InputStream input = new FileInputStream(ExcelLocation);
  readWorkBook = Workbook.getWorkbook(input);
  Sheet readSheet = readWorkBook.getSheet(1);
  for (int i = 0; i < readSheet.getRows(); i++) {
  Cell cellInput = readSheet.getCell(4, i);
  Cell dataSwitch=readSheet.getCell(3, i); //设置了控制是否执行案例的开关,填enable则执行
  if (cellInput.getContents().contains("|")&&dataSwitch.getContents().equals("enable")) {
  oraginalData = cellInput.getContents();
  // System.out.println(oraginalData);
  temp = oraginalData.split("\\|", 10);
  list.add(temp);
  int row=i+1;
  System.out.println("将第"+row+"行数据添加到list成功");
  //                    for (int j = 0; j < temp.length; j++) {
  //                        System.out.println(temp[j]);
  //                    }
  }
  }
  } catch (Exception e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  }
  return list;
  }
  我将测试参数用“|”隔开,每个位置一个参数,读出单元格的数据后,用split方法将一串字符分割存到数组,然后再把数组存到list里面,作为junit执行需要的参数,每个数组作为一条测试用例的输入数据。
  写入Excel的方法如下:
   /**
  * 往excel写数据
  * @param data 需要写入的字符串
  * @param column 目标单元格列号
  * @param row     目标单元格行号
  * @param ExcelName  文件路径
  */
  public void writeExcel(String data,int column,int row,String ExcelName) {
  try {
  InputStream input = new FileInputStream(ExcelName);
  Workbook readWorkBook = Workbook.getWorkbook(input);
  Sheet readSheet = readWorkBook.getSheet(1);
  WritableWorkbook wwb = Workbook.createWorkbook(new File(ExcelName), readWorkBook);
  WritableSheet ws = wwb.getSheet(1);
  Label label = new Label(column,row, data);
  ws.addCell(label);
  int ji=row+1;
  System.out.println("填充第"+ji+"行表格成功");
  wwb.write();
  System.out.println("写入表格并保存成功");
  wwb.close();
  } catch (Exception e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  }
  }
  写这里我遇到了一个问题,就是一开始我是读取输入的文件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,参考网上资料后,完美解决问题。只要加一句driver.switchTo().frame(1)切换frame后就能定位到了。
  第二,是元素ID是会变化的,类似于这种value_1、value_2,就是同一个输入框,列表不同行的ID是不一样的,为了能够复用代码,在网上找到了使用findElement(By.cssSelector("Input[id^=\"value_\"]"))的方法完美解决。
  "Input[id^=\"value_\"表示,id的头为value_的input元素。类似的,我又写了个新增数据字典的方法
   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");就可以了。代码如下
   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("123456");//        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());
  }
  }
  }
  至此,第一次自动化尝试成功,以后测试会方便很多,还可以根据需要再做调整,增加输入参数扩展都很方便。在此再次谢谢广大肯分享自己的心得体会和问题解决方案的网友们,特别感谢上述参考链接的作者们,谢谢。
  代码已去掉一些敏感信息,不便之处,敬请谅解。

版权声明:本文出自51Testing会员投稿,51Testing软件测试网及相关内容提供者拥有内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号