Package com.baidu.qa.service.test.execute

Source Code of com.baidu.qa.service.test.execute.ServiceInterfaceCaseTest

package com.baidu.qa.service.test.execute;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.databene.contiperf.PerfTest;
import org.databene.contiperf.junit.ContiPerfRule;
import org.databene.contiperf.timer.ConstantTimer;
import org.databene.contiperf.timer.RandomTimer;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import com.baidu.qa.service.test.client.HttpInvokerServiceClientImpl;
import com.baidu.qa.service.test.client.HttpServiceClientImpl;
import com.baidu.qa.service.test.client.JsonRpcServiceClientImpl;
import com.baidu.qa.service.test.client.ServiceInterfaceClient;
import com.baidu.qa.service.test.client.SoapServiceClientImpl;
import com.baidu.qa.service.test.dto.*;
import com.baidu.qa.service.test.login.*;
import com.baidu.qa.service.test.parser.CaseFolderParser;
import com.baidu.qa.service.test.parser.CaseFolderParserImpl;

import com.baidu.qa.service.test.setup.SetUp;
import com.baidu.qa.service.test.setup.SetUpImpl;
import com.baidu.qa.service.test.teardown.TearDown;
import com.baidu.qa.service.test.teardown.TearDownImpl;
import com.baidu.qa.service.test.util.*;
import com.baidu.qa.service.test.verify.Verify;
import com.baidu.qa.service.test.verify.VerifyImpl;



/**
*
* @author xuedawei
* @date 2013-8-9
* @classname ServiceInterfaceCaseTest
* @version 1.0.0
* @desc service-ddt:service data driver test,是将一系列service接口的自动化测试,统一为数据驱动的模式;
* 采用了junit的参数化模式,将service接口测试所需的参数、验证结果等依次从外部case文件加载后,执行测试
* @desc 测试对象:HTTP(POST/GET)接口,JSON-RPC接口,SOAP接口
* @desc 测试结果验证模式:接口返回字符串,返回json,mysql结果
*/
@RunWith(Parameterized.class)
public class ServiceInterfaceCaseTest {
 

  private static Log log = LogFactory.getLog(ServiceInterfaceCaseTest.class);
  /**
   * case重复执行的次数,默认是1次
   */
  private static int invocations = 1;
  /**
   * 需要权限的service,且不方便做登录,可以手工准备cookie文件,加以复用
   */
  private static String cookiefile = "";
  /**
   * 是否执行sql的开关项,统一设置
   */
  public static boolean is_execute_sql = true;
 
  /**
   * 是否需要在测试http接口的时候自动登录
   */
  public static boolean is_auto_login = false;

  private CaseData casedata;
  private CaseSuite casesuite;
  private boolean isfirstinsuite;
  private boolean islastinsuite;
  private boolean isnewserver;

  /**
   * CASEPATH为外部case的路径,默认的是project的case目录,如果test.properties中指定则替换
   */
  public static String CASEPATH = System.getProperty("user.dir") + "/case";
  /**
   * RUNPATH为CASEPATH下有多个子目录的情况下,特别指定1个或多个子目录单独执行,在test.properties中指定
   */
  public static String RUNPATH = null;
 
  private ServiceInterfaceClient siclient = null;
  private SetUp setup = new SetUpImpl();
  private Verify verify = new VerifyImpl();
  private TearDown teardown = new TearDownImpl();

 
 
  /**
   * JUnit参数化,case文件中的数据,被初始化到数组
   * @param caselocation case的绝对路径
   * @param casesuite suite对象,case按照不同suite归类执行
   * @param casedata case数据,包含了接口请求action,接口协议类型
   * @param isfirstinsuite 标识case是否为一个suite用途是在此时机做suite级别的初始化
   * @param islastinsuite 表示case是否为一个suite分组的最后一个case
   * @param desc case文本描述
   */
  public ServiceInterfaceCaseTest(String caselocation, CaseSuite casesuite,
      CaseData casedata, boolean isfirstinsuite, boolean islastinsuite,
      String desc) {
    this.casesuite = casesuite;
    this.casedata = casedata;
    this.isfirstinsuite = isfirstinsuite;
    this.islastinsuite = islastinsuite;
   
    String service_type = casesuite.config.getCasetype();
    if (service_type.equalsIgnoreCase(Constant.CASETYPE_HTTP)) {
      siclient = new HttpServiceClientImpl();
    } else if (service_type.equalsIgnoreCase(Constant.CASETYPE_SOAP)) {
      siclient = new SoapServiceClientImpl();
    } else if (service_type.equalsIgnoreCase(Constant.CASETYPE_JSON)) {
      siclient = new JsonRpcServiceClientImpl();
    } else if (service_type.equalsIgnoreCase(Constant.CASETYPE_HTTPINVOKER)) {
      siclient = new HttpInvokerServiceClientImpl();
    }
  }

 
  /**
   * 基础配置信息初始
   */
  static {
    // 从test.properties中读取case路径等
    try {
      InputStream cfin = new BufferedInputStream(new FileInputStream(
          System.getProperty("user.dir") + Constant.FILENAME_TEST));
      Properties cfInfo = new Properties();
      cfInfo.load(cfin);
     
      if (cfInfo.containsKey("casepath")) {
        String path = cfInfo.getProperty("casepath").trim();
        if (path != null && path.length() != 0) {
          CASEPATH = path;
        }else{
          log.error("[CASEPATH IN TEST.PROPERTIES IS NULL]");
          throw new RuntimeException("CASEPATH IN TEST.PROPERTIES IS NULL!!");
        }
      }
      //suite
      if (cfInfo.containsKey("runpath")) {
        String path = cfInfo.getProperty("runpath").trim();
        if (path != null && path.length() != 0) {
          RUNPATH = path;
        }
      }
     
      //case执行的次�?
      if (cfInfo.containsKey("invocations")) {
        String tmp = cfInfo.getProperty("invocations").trim();
        if (tmp != null && tmp.length() != 0) {
          try{
            invocations = Integer.parseInt(tmp);
          }catch(Exception e){
            invocations = 1;
          }
        }
      }
     
      //是否读取cookie文件的方式,要得到路�?
      if (cfInfo.containsKey("cookiefile")) {
        String tmp = cfInfo.getProperty("cookiefile").trim();
        if (tmp != null && tmp.length() != 0) {
          cookiefile = tmp;
        }
      }
     
     
      if (cfInfo.containsKey("is_execute_sql") &&
          cfInfo.getProperty("is_execute_sql").trim().equalsIgnoreCase("false")) {
        is_execute_sql = false;
      }

      if (cfInfo.containsKey("is_auto_login") &&
          cfInfo.getProperty("is_auto_login").trim().equalsIgnoreCase("true")) {
        is_auto_login = true;
      }
     
      cfin.close();
      log.info("[CASE PATH]:" + CASEPATH);
      log.info("[CASE SUITE PATH]:" + RUNPATH);
    } catch (Exception e) {
      log.error("[GET CONFIG FROM TEST.PROPERTIES ERROR]:", e);
      throw new RuntimeException(e);
    }
  }
 
 

  /**
   * 需要登录权限才能运行的http接口,需要实现Login的接口,返回登录成功后的cookie,为case所复用
   * 如果不做自动登录的话,但也需要权限,则可手工copy可用cookie至一个文件,并在test.properties中设置cookiefile=的路径
   */
  private void setLoginCookie() {
   
    try {
      String cookie = "";
      if(casesuite.config.getCasetype().equalsIgnoreCase(Constant.CASETYPE_HTTP) == false){
        log.info("[CASE TYPE IS NOT HTTP PROTOCOL , SKIP LOGGING..]");
      }else{
        if(is_auto_login){
          Login login = new LoginImpl();
          cookie = login.loginAndGetCookie();
        }else{
          if(!cookiefile.equals("")){
            cookie = FileUtil.readFileByLines(new File(cookiefile));
          }
        }
      }
     
      casesuite.config.getVariable().put("cookie", cookie);
    } catch (Exception e) {
      throw new AssertionError("[login error and stop run case]");
    }

  }
 
 


  /**
   * 使用参数化的方式将case数据载入到数组
   * @return 二维数组
   * @throws Exception
   */
  @Parameters(name = "{index}][{0}][{5}")
  public static Collection<Object[]> loadTestData() throws Exception {
   
    log.info("[loading test cases from case folders...]");
    CaseFolderParser cfp = new CaseFolderParserImpl();
    List<CaseSuite> casesuitelist = null;
   
    if (RUNPATH != null && RUNPATH.trim().length() != 0) {
      log.info("use runpath load cases" + RUNPATH);
      casesuitelist = cfp.getCasesuiteFromPathlist(RUNPATH, CASEPATH);
    } else {
      casesuitelist = cfp.getCasesuiteFromFolder(CASEPATH);
    }

    if(casesuitelist == null || casesuitelist.isEmpty()){
      throw new AssertionError("[CASES NOT FOUND...]");
    }

    int casenum = 0;
    for (int i = 0; i < casesuitelist.size(); i++) {
      casenum += casesuitelist.get(i).getCasedatalist().size();
    }
   
    casenum = casenum * invocations;
   
    Object[][] objects = new Object[casenum][6];
    casenum = 0;

    for (int i = 0; i < casesuitelist.size(); i++) {
      for(int n = 0; n < invocations;n++){
        for (int j = 0; j < casesuitelist.get(i).getCasedatalist().size(); j++) {
          objects[casenum][0] = casesuitelist.get(i).getCasedatalist().get(j).getCaselocation();
          objects[casenum][1] = casesuitelist.get(i);
          objects[casenum][2] = casesuitelist.get(i).getCasedatalist().get(j);
          objects[casenum][3] = false;
          objects[casenum][4] = false;
          objects[casenum][5] = FileUtil.transCoding(casesuitelist.get(i).getCasedatalist().get(j).getDesc());
//          objects[casenum][6] = false;
//          objects[casenum][7] = null;

          if (j == 0 && n ==0) {
            objects[casenum][3] = true;
          }
          if (j == casesuitelist.get(i).getCasedatalist().size() - 1 && n == invocations - 1) {
            objects[casenum][4] = true;
          }
          casenum++;
        }
      }
    } 
   
    log.info("[load testcases from case folders done!!]");
    return Arrays.asList(objects);
  }

 
 
 
 
  @Before
  /**
   * test前置工作,主要处理测试准备的一些工作
   */
  public void setup() {
    log.info("===============================start testing===============================");
    log.info("[test case info]:caseid=" + casedata.getCaseid() + ",casepath="+ casedata.getCaselocation());
    // 第一步:清理output文件
    try{
      FileUtil.deleteInFolder(casedata.getCaselocation()+ Constant.FILENAME_OUTPUT);
    }catch(Exception e){
      log.error("[delete output folder error]", e);
    }
   
    //第二部:有权限控制的地方需要设置登录cookie,且避免重复登录,在一个suite内第一个case需要登录
    try{
      if (isfirstinsuite) {
        setLoginCookie();
      }
    }catch(Exception e){
      throw new AssertionError("[Login error]"+e.getMessage());
    }
   
    // 第三步:如果是suite,则执行suite级别的teardown
    if (isfirstinsuite || casesuite.getConfig().getSuitetype().equalsIgnoreCase(Constant.V_CONFIG_SUITETYPE_BATCH)) {
      log.info("[test casesuite path]:" + casesuite.getCasesuitepath());
      // 如果没有变量替换,就先执行teardown
      if (!casedata.isHasVar() && !casesuite.getConfig().isHasVar()) {
        try {
          teardown.cleanTestData(casesuite.getSuiteteardown(),casesuite.config, casesuite.getVarGen());
        } catch (Exception e) {
          log.error("[EXCUTE SUITE TEARDOWN ERROR]:", e);
        }
      }
    }
    // 第四步:先清理脏数据,如果没有变量替换先进行case数据清理
    if (!casedata.isHasVar() && !casesuite.getConfig().isHasVar()) {
      teardown.cleanTestData(casedata.getTeardown(), casesuite.config, casedata.getVarGen());
    }
    // 第五步:如果是suite的第�?��case或�?是batch的方式,则执行suite级别的setup
    if (isfirstinsuite|| casesuite.getConfig().getSuitetype().equalsIgnoreCase(Constant.V_CONFIG_SUITETYPE_BATCH)) {
      log.info("[begin set case suite data]");
      try {
        setup.setTestData(casesuite.getSuitesetup(), casesuite.config,casesuite.getVarGen());
      } catch (Exception e) {
        log.error("[EXCUTE SUITE SETUP ERROR]:", e);
      }
      // suite的setup之后等待时间
      if (casesuite.config.getSuite_before_wait_time() != 0) {
        try {
          log.debug("suite sleep before cases "+ casesuite.config.getSuite_before_wait_time()/ 1000 + "s");
          Thread.sleep(casesuite.config.getSuite_before_wait_time());
        } catch (InterruptedException e) {
          log.error("[waite before casesuite error]:", e);
        }
      }
    }
   
    log.info("[test case path]:" + casedata.getCaselocation());
    log.info("[test case id]:" + casedata.getCaseid());
    log.info("[test case desc]:"+ FileUtil.transCoding(casedata.getDesc()));
    log.info("[test case url]:" + casesuite.config.getHost()+ casedata.getAction());

   
    try {
      log.info("[BEGIN SET TEST DATA]");
      setup.setTestData(casedata.getSetup(), casesuite.config, casedata.getVarGen());
      log.info("[SET TEST DATA DONE]");
    } catch (Exception e) {
      log.error("[EXCUTE CASE SETUP STEP ERROR]:", e);
    }

  }

 
 
  /**
   * Data-driver方式驱动测试多次执行
   * timout设置为30s内case未结束则fail
   */
  @Test(timeout=30000)
  public void testCase() {
   
    Object resp = null;
   
    try {
      //增加休眠环节,主要是避免大系统的数据延迟给测试带来困扰
      if (casesuite.config.getBefore_wait_time() != 0) {
        log.info("[case sleep before request for "+ casesuite.config.getBefore_wait_time() / 1000 + "s]");
        Thread.sleep(casesuite.config.getBefore_wait_time());
      }
      //request
      resp = siclient.invokeServiceMethod(casedata,casesuite.config);
      log.info("[THE SERVICE INTERFACE RESPONSE]:" + resp);
     
      // sleep after request
      if (casesuite.config.getAfter_wait_time() != 0) {
        log.debug("case sleep after request for "+ casesuite.config.getAfter_wait_time() / 1000 + "s");
        Thread.sleep(casesuite.config.getAfter_wait_time());
      }
    } catch (Exception e) {
      log.error("[SERVICE INTERFACE REQUEST ERROR]", e);
      throw new AssertionError("SERVICE INTERFACE REQUEST ERROR" + e.getMessage());
    }
   
   
    try {
      //记录接口的实际返回
      FileUtil.rewriteFile(casedata.getCaselocation()+ Constant.FILENAME_OUTPUT,
          Constant.FILENAME_ACTUAL_RESULT, resp.toString());
      //记录diff文件以辅助于对应查找区别
      StringDiffUtil diff = new StringDiffUtil();
      for(File file : casedata.getExpect()){
        if(FileUtil.getFileSuffix(file).equals(Constant.FILE_TYPE_RESPONSE)){
          FileUtil.rewriteFile(casedata.getCaselocation()+ Constant.FILENAME_OUTPUT,
              Constant.FILENAME_DIFF_RESULT, diff.diff_prettyHtml(diff.diff_main(resp.toString(), FileUtil.readFileByLinesWithBOMFilter(file))));
          break;
        }
      }
    } catch (Exception e) {
      //这一步出错不影响测试继续执行
      log.error("[interface's response record or diff error]", e);
    }


    //验证环节
    try {
      //返回为null不能作为fail依据
      if (resp == null) {
        log.error("[interface response result is null]");
      } else {
        log.info("[BEGIN EXECUTE VERIFY STEP] "+casedata.getCaselocation());
        verify.verify(casedata.getExpect(), resp.toString(),
            casedata.getCaselocation(), casesuite.config, casedata.getVarGen());
        log.info("[VERIFY TEST RESULT DONE] ");
      }

    } catch (Exception e) {
      log.error("[assert error]:", e);
      throw new AssertionError("TEST RESULT VERIFY FAIL:" + e);
    }
  }

 
 
 
 
  /**
   * case执行结束后的收尾工作,主要为数据清理的环节
   */
  @After
  public void teardown() {
   
    //清理掉已经用过的测试数据
    try {
      log.info("[BEGIN EXCUTE CASE TEARDOWN STEP]");
      teardown.cleanTestData(casedata.getTeardown(), casesuite.config, casedata.getVarGen());
      log.info("[CASE TEARDOWN STEP EXECUTED SUCCESS]");
    } catch (Exception e) {
      log.error("[EXCUTE CASE TEARDOWN ERROR] ", e);
    }
   
    // suite级别的teardown
    if (islastinsuite|| casesuite.getConfig().getSuitetype().equalsIgnoreCase(Constant.V_CONFIG_SUITETYPE_BATCH)) {
     
      try {
        log.info("[BEGIN EXCUTE CASESUITE TEARDOWN STEP]");
        log.info("[SLEEP SOME TIMES] " + casesuite.config.getSuite_after_wait_time() / 1000+ "s");
        Thread.sleep(casesuite.config.getSuite_after_wait_time());
      } catch (InterruptedException e) {
        throw new RuntimeException("Thread error");
      }
     
     
      try {
        teardown.cleanTestData(casesuite.getSuiteteardown(), casesuite.config,casesuite.getVarGen());
      } catch (Exception e) {
        log.error("[EXCUTE SUITE TEARDOWN ERROR]:", e);
      }
    }
   
  }
}
TOP

Related Classes of com.baidu.qa.service.test.execute.ServiceInterfaceCaseTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.