ITester接口测试框架 (三) : 框架实现细节

项目结构

结构图

这里写图片描述


框架实现

1.数据准备 和 参数输入

数据准备有三种方式:

  • 一:通过访问数据库,获取我们需要的接口测试参数,比如测试登录接口,我们要提前获得 用户名和密码,然后才能连同我们的url发送给服务端。

要想访问数据库,必须要先与数据库建立连接,我这里采用的是JDBC 和C3P0,可以参考我之前的blog
Java通过JDBC 进行MySQL数据库操作
Java数据库连接池 学习笔记

  • 二:直接将所需要的数据写入到xml或者excel中,然后写一个工具类直接去读取就行。

例如 :要准备 测试接口输入参数为:email和password

(1)编写paramsData.xml,将上述参数放在xml中进行管理

<?xml version="1.0" encoding="UTF-8"?>
<map>   
    <bean beanName="signIn">     
        <locator name="email" value="charlie.chen@dji.com"></locator>
        <locator name="password" value="123456"></locator>      
    </bean>
</map>

(2)封装一个XmlUtil工具类负责读取xml ,使用第三方的jar包dom4j,XmlUtil中readXMLDocument方法返回值为Map

public static Map<String, String> readXMLDocument(String xmlPath, String beanName) throws IOException {

}

上述readXMLDocument方法中,参数xmlName为xml文件的名字; 参数beanName为xml文件中节点的名称。

  • 三:通过xml管理测试数据,也可以用Excel进行管理

和xml管理数据类似:封装一个ExcelUtil工具类负责读取excel ,使用第三方的jar包poi,ExcelUtil中readExcel方法返回值为List

// 读取Excel中数据
public static List<ParamBean> readExcel(String excelPath) throws Exception {

}

2.请求执行

(1)封装一个CookieUtil工具类,通过CookieStore储存cookie
CookieUtil类中setCookieStore方法返回值为CookieStore

**
 * 将服务端返回的SessionID存储在CookieStore中
 * @author Charlie.chen
 * @date 2016-10-31
 *
 */
public class CookieUtil {

    private static CookieStore cookieStore = null;
    private static LogUtil log = new LogUtil(CookieUtil.class);


    /*
     * 通过CookieStore储存cookie
     */
    public static CookieStore setCookieStore(HttpResponse httpResponse) {

        log.info("setCookieStore");
        cookieStore = new BasicCookieStore();
        // JSESSIONID
        String setCookie = httpResponse.getFirstHeader("Set-Cookie").getValue();
        String JSESSIONID = setCookie.substring("JSESSIONID=".length(),
        setCookie.indexOf(";"));
        log.debug("JSESSIONID:" + JSESSIONID);

        // 新建一个Cookie
        BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", JSESSIONID);
        cookie.setVersion(0);
        cookie.setDomain("127.0.0.1");
        cookie.setPath("/CwlProClient");

        cookieStore.addCookie(cookie);
        return cookieStore;
    }
}

上述setCookieStore方法中,httpResponse参数为服务端响应值,类型为HttpResponse

(2)用httpClient简单封装一个httpClientUtil工具类有get.post,put,delete方法

public static CloseableHttpResponse doGet(String url, Map<String, String> paramsMap, CloseableHttpClient httpclient, CookieStore cookieStore) {
}

public static CloseableHttpResponse doPost(String url, Map<String, String> paramsMap, CloseableHttpClient httpclient,CookieStore cookieStore) {
}

public static CloseableHttpResponse doPut(String url, Map<String, String> paramsMap, CloseableHttpClient httpclient, CookieStore cookieStore) {
}

public static CloseableHttpResponse doDelete(String url, Map<String, String> paramsMap, CloseableHttpClient httpclient, CookieStore cookieStore) {
}

/**
* 封装一个获取请求实体的方法
* @param params
* @param ucode
* @return
*/
public static UrlEncodedFormEntity getFormEntity(Map<String, String> paramsMap, Charset... ucode) {
}

3.结果解析 和 验证

(1)将从服务端返回的HttpResponse结果解析为ResponseBean对象

public class ReponseUtil {

    private static LogUtil log = new LogUtil(ReponseUtil.class);
    private static ResponseBean responseBean=null;

    public static ResponseBean setResponseBean(CloseableHttpResponse httpResponse) {

        // 使用响应对象获取响应实体
        HttpEntity entity = httpResponse.getEntity();
        if (entity != null)
            try {
                // 将响应实体转为字符串
                String responseString = EntityUtils.toString(entity, "utf-8");
                String rs = responseString.replace("\r\n", "");

                responseBean = new ResponseBean();
                responseBean.setStatus(httpResponse.getStatusLine().getReasonPhrase());
                responseBean.setStatusCode(Integer.toString(httpResponse.getStatusLine().getStatusCode()));
                responseBean.setBody(rs);

                log.info("\n" + "***************************返回开始**********************************" + "\n"
                        + httpResponse.getStatusLine().getReasonPhrase() + "\n"
                        + Integer.toString(httpResponse.getStatusLine().getStatusCode()) + "\n" + "Context" + rs + "\n"
                        + "***************************返回结束**********************************");

                HeaderIterator iterator = httpResponse.headerIterator();
                while (iterator.hasNext()) {
                    log.debug("\t" + iterator.next());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        return responseBean;
    }
}

(2)结果验证
主要验证 HttpResponse的状态status,状态码statusCode和 响应实体body,通过第三方断言jar包AsertJ

// add Assert
Assert.assertEquals("OK", responseBean.getStatus());
Assert.assertEquals("200", responseBean.getStatusCode());
Assert.assertEquals("dsgfdfgdfsdfdgfdg", responseBean.getBody());

4.测试用例

测试用例管理使用了testNG管理 ,使用了TestNG参数化测试,通过xml文件来执行case

(1)测试case脚本

public class NewTest {

    static CookieStore cookieStore=null;

    static CloseableHttpClient httpclient=null;

    @Test
    public void test() {

        try {
            String url = PropertiesUtil.getValue("url","config.properties");

            String xmlPath=NewTest.class.getClassLoader().getResource("paramData.xml").getPath();

            Map<String, String> paramsMap = XmlUtil.readXMLDocument(xmlPath, "signIn");

            httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
            CloseableHttpResponse httpResponse = HttpClientUtil.doPost(url, paramsMap, httpclient, cookieStore);

            ResponseBean responseBean = ReponseUtil.setResponseBean(httpResponse);

            // add Assert
            Assert.assertEquals("OK", responseBean.getStatus());
            Assert.assertEquals("200", responseBean.getStatusCode());
            Assert.assertEquals("dsgfdfgdfsdfdgfdg", responseBean.getBody());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @BeforeClass
    public void beforeClass() {
    }

    @AfterClass
    public void afterClass() {
    }

    @BeforeTest
    public void beforeTest() {
    }

    @AfterTest
    public void afterTest() {
    }

    @BeforeSuite
    public void beforeSuite() {
        /*
        * 登录进入系统获取JSESSIONID放入到CookieStore中
        * */
    }

    @AfterSuite
    public void closeClient() {
        try {
            // 关闭流并释放资源
            httpclient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(2)testng.xml文件的编写

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="false" preserve-order="true">

  <test name="Test">
    <classes>
      <class name="com.dji.itester.cases.NewTest">
         <methods>
              <include name="test" />
         </methods>
      </class>
    </classes>
  </test> 
</suite> 

右键->run as ->TestNG Suite,这个场景的的测试用例就可以运行了

5.失败用例重跑

关于失败用例重跑,在我前面的blog TestNG实现用例运行失败自动截图和重跑 写的很清楚了,这里就不详说了,大概步骤如下:

(1)新建TestNGRetry类继承IRetryAnalyzer,实现用例失败自动重跑逻辑
(2)添加用例重跑监听器RetryListener,用例失败自动重跑功能
(3)在testng.xml文件中配置自己编写的监听器

    <listeners>
        <listener class-name="com.dji.itester.runfail.TestNGListener" />
        <listener class-name="com.dji.itester.runfail.RetryListener"/>
    </listeners>

6.源码管理 和 Jenkins配置

(1)源码管理
将代码上传到github上进行托管,关于github的使用参考我前面的blog Git 学习笔记

(2)Jenkins配置
运行jenkins,首先创建一个job为ITester-DJI
这里写图片描述

将代码上传到github上进行托管,然后在jenkins上配置clone 到你本地或者远程的jenkins来:
这里写图片描述

构建触发器
Poll SCM: 定时检查源码变更(根据SCM软件的版本号),如果有更新就checkout最新code下来,然后执行构建动作。Build periodically:周期进行项目构建(它不care源码是否发生变化)
我的配置如下: 每天凌晨2:00进行一次构建

这里写图片描述

构建
这里写图片描述

构建后操作,发送邮件

7.测试报告和邮件

这里用到第三方的jar包ReportNG,对测试报告进行定制化。添加插件,关联testNg.xml,添加ReportNg的监听器,修改最后的TestNG的报告。

    <build>
        <plugins>
            <!-- 添加插件,关联testNg.xml,添加ReportNg的监听器,修改最后的TestNG的报告 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
                <configuration>

                    <forkMode>once</forkMode>  
                    <argLine>-Dfile.encoding=UTF-8</argLine> 

                    <suiteXmlFiles>
                        <!--<suiteXmlFile>testng.xml</suiteXmlFile>  -->
                        <suiteXmlFile>src/test/java/com/dji/itester/testSuites/${xmlFileName}</suiteXmlFile> 
                    </suiteXmlFiles>

                    <properties>
                        <property>
                            <name>usedefaultlisteners</name>
                            <value>false</value>
                        </property>
                        <property>
                            <name>listener</name>
                            <value>org.uncommons.reportng.HTMLReporter,
                                org.uncommons.reportng.JUnitXMLReporter</value>
                        </property>
                    </properties>

                    <workingDirectory>target/</workingDirectory>
                </configuration>
            </plugin>


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>


        </plugins>
    </build>

测试报告:

这里写图片描述


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值