服务端的测试,大多数内容都围绕着接口展开。对于接口测试,无非也是功能、自动化、性能测试为主,偶然想到一个问题,如果能写一个用例,在功能、自动化、性能三者的测试场景中重复使用,肯定能省去非常多的时间。

总体思路跟之前的接口和性能框架一样,通过总的测试项目中把接口功能封装好,留出来测试参数。功能测试就写方法调用然后人肉检查,自动化的话把接口响应拿出来,然后验证各种数据,性能直接使用性能框架直接调用该方法即可。

花了点时间,做了一个Demo,分享给大家。

这是一个简易的接口请求方法,其中main方法里面是功能测试执行代码,用例是文档形式,这里就不写了:

public class Headgear extends NajmBase {    public Headgear(NajmBase najmBase) {        this.loginKey = najmBase.loginKey;        this.args = najmBase.args;        this.user_id = najmBase.user_id;    }    private static NajmBase base = NajmBase.getBase(0);    public static Headgear drive = new Headgear(base);    /**     * 当前正在使用的头套     */    public int usingHeadgearId;    //    public JSONObject headgearInfo = new JSONObject();    public Map<Integer, Long> headgearInfo = new HashMap<>();    public static void main(String[] args) {//        NajmBase.getUserBalance(base.user_id);//        int type = 1, id = 36, packageId = 60, num = 1, price = 1;//        NajmBase base1 = new NajmBase(V580User.getUserName(0));//        Headgear headgear = new Headgear();//        headgear.switchHeadgear(34);//        output(headgear.getHeadgearInfo());//        output(headgear.getUsingHeadgearId());//        output(base1.loginResponse);//        drive.getAllHeadgear();//        new MallBase(base).buy(type, id, packageId, num, price);//        drive.getUserHeadgearInfo();//        NajmBase.getUserBalance(base.user_id);//        drive.getUserHeadgearInfo();//        drive.getOnsaleHeadgear();        int times = 0;        while (true) {            times++;            int type = 1, id = getRandomInt(2) == 1 ? 34 : 36, packageId = id == 34 ? 56 : 60, num = 1, price = 1;            long deadtime1 = drive.getHeadgearInfo().get(id);            Verify verify = new Verify(new MallBase(base).buy(type, id, packageId, num, price));            drive.getUserHeadgearInfo();            long deadtime2 = drive.getHeadgearInfo().get(id);            if (deadtime2 - deadtime1 != DAY) break;        }        output("一共进行了:" + times);//        output(drive.getHeadgearInfo());//        output(drive.usingHeadgear);//        output(drive.loginKey);//        output(drive.args);//        output(base.loginResponse.getJSONObject(DATAINFO).getJSONObject("headGear").getInt("id"));        testOver();    }    /**     * 获取所有头套信息,包括下架的     *     * @return     */    public JSONObject getAllHeadgear() {        String url = HOST + HeadgearApiPath.GET_ALL_HEADGEAR;        HttpGet httpGet = getHttpGet(url);        JSONObject response = getHttpResponseEntityByJson(httpGet);        output(response);        return response;    }    /**     * 用户切换头套接口     *     * @param hid     * @return     */    public JSONObject switchHeadgear(int hid) {        String url = HOST + HeadgearApiPath.SWITCH_HEADGEAR + hid + changeJsonToArguments(args);        HttpPost httpPost = getHttpPost(url);        JSONObject response = getHttpResponseEntityByJson(httpPost);//        output(response);        return response;    }    /**     * 获取用户头套信息     *     * @return     */    public JSONObject getUserHeadgearInfo() {        sleep(1);        String url = HOST + HeadgearApiPath.GET_USER_HEADGEAR;        JSONObject response = getHttpResponseEntityByJson(getHttpGet(url, args));        output(response);        if (isRightResponse(response)) {            headgearInfo.clear();            JSONArray jsonArray = response.getJSONArray(DATAINFO);            jsonArray.forEach(json -> {                    JSONObject jsonObject = JSONObject.fromObject(json.toString()) ;                    String name = jsonObject.getString("name") ;                    long deadTime = jsonObject.getLong("deadlineTime") ;                    int headgearId = jsonObject.getInt("goodId") ;                    int use = jsonObject.getInt("isUse") ;            if (use == 1) usingHeadgearId = headgearId;            headgearInfo.put(headgearId, deadTime);            output(name, headgearId, getTimeByTimestamp(deadTime));        } );        }        return response;    }    /**     * 获取在售的头套的列表     *     * @return     */    public JSONObject getOnsaleHeadgear() {        String url = HOST + HeadgearApiPath.GET_ONSALE_HEADGEAR;        JSONObject response = getHttpResponseEntityByJson(getHttpGet(url, args));        output(response);        return response;    }    public int getUsingHeadgearId() {        getUserHeadgearInfo();        return usingHeadgearId;    }    public Map<Integer, Long> getHeadgearInfo() {        getUserHeadgearInfo();        return headgearInfo;    }}复制代码

下面是基于该功能的自动化测试用例,main方法里面是调试用例的过程,执行用例的方法在之前的文章写过,利用反射去记录用例信息和执行测试用例,并保存测试结果,输出测试报告,异常预警等等:

/** * 用户0-10 */public class HeadgearCase extends SourceCode {    static HeadgearCase headgearCase = new HeadgearCase();    static NajmBase base = new NajmBase(V580User.getUserName(0));    static Headgear drive = new Headgear(base);    public static void main(String[] args) {//        headgearCase.testDemo001();//        headgearCase.testDemo002();//        headgearCase.testDemo003();//        headgearCase.testDemo004();        headgearCase.testDemo005();//        headgearCase.testDemo006();        ApiLibrary.testOver();    }    /**     * 获取所有头套信息用例     */    public void testDemo001() {        String label = "获取所有头套信息用例" + TAB + Thread.currentThread().getStackTrace()[1];        Verify verify = new Verify(drive.getAllHeadgear());        JSONObject result = new JSONObject();        result.put("状态码为0", verify.isRight());        result.put("包含数组", verify.isArray("heads"));        result.put("包含已下架的头套", verify.isContains("自动化专用3"));        result.put("包含正在出售的头套", verify.isContains("自动化专用1"));        MySqlTest.saveTestResult(label, result);    }    /**     * 获取在售的头套用例     */    public void testDemo002() {        String label = "获取在售的头套用例" + TAB + Thread.currentThread().getStackTrace()[1];        Verify verify = new Verify(drive.getOnsaleHeadgear());        JSONObject result = new JSONObject();        result.put("状态码为0", verify.isRight());        result.put("包含数组", verify.isArray("dataInfo"));        result.put("不包含已下架的头套", !verify.isContains("自动化专用3"));        result.put("包含正在出售的头套", verify.isContains("自动化专用1"));        result.put("包含描述信息", verify.isContains("测试10天"));        MySqlTest.saveTestResult(label, result);    }    /**     * 获取用户头套信息用例     */    public void testDemo003() {        String label = "获取用户头套信息用例" + TAB + Thread.currentThread().getStackTrace()[1];        Verify verify = new Verify(drive.getUserHeadgearInfo());        JSONObject result = new JSONObject();        result.put("状态码为0", verify.isRight());        result.put("用户头套正常", verify.isContains("自动化专用1"));        result.put("用户佩戴正常", verify.isContains("\"isUse\":1"));        result.put("头套套餐正常", verify.isContains("测试1天"));        MySqlTest.saveTestResult(label, result);    }    /**     * 余额不足购买用例     */    public void testDemo004() {        String label = "余额不足购买用例" + TAB + Thread.currentThread().getStackTrace()[1];        NajmBase base = new NajmBase(V580User.getUserName(1));        int type = 1, id = 36, packageId = 60, num = 1, price = 1;        Verify verify = new Verify(new MallBase(base).buy(type, id, packageId, num, price));        JSONObject result = new JSONObject();        result.put("状态码为35", 35 == verify.getCode());        MySqlTest.saveTestResult(label, result);    }    /**     * 正常购买用例     */    public void testDemo005() {        String label = "正常购买用例" + TAB + Thread.currentThread().getStackTrace()[1];        int type = 1, id = getRandomInt(2) == 1 ? 34 : 36, packageId = id == 34 ? 56 : 60, num = 1, price = 1;        int balance = NajmBase.getUserBalance(drive.user_id);        long deadtime1 = drive.getHeadgearInfo().get(id);        Verify verify = new Verify(new MallBase(base).buy(type, id, packageId, num, price));        drive.getUserHeadgearInfo();        long deadtime2 = drive.getHeadgearInfo().get(id);        int balance1 = NajmBase.getUserBalance(drive.user_id);        JSONObject result = new JSONObject();        result.put("状态码为0", verify.isRight());        result.put("截止日期正确", (deadtime2 + EMPTY).equals(verify.getValue("deadlineTime")));        result.put("头套日期增加正常", deadtime2 - deadtime1 == DAY);        result.put("用户余额减少正常", balance - balance1 == 1);        MySqlTest.saveTestResult(label, result);    }    /**     * 用户切换头套用例     */    public void testDemo006() {        String label = "用户切换头套用例" + TAB + Thread.currentThread().getStackTrace()[1];        drive.getAllHeadgear();        int id1 = drive.getUsingHeadgearId() == 34 ? 36 : 34;        Verify verify = new Verify(drive.switchHeadgear(id1));        int id2 = drive.getUsingHeadgearId();        JSONObject result = new JSONObject();        result.put("状态码为0", verify.isRight());        result.put("头套切换成功", id1 == id2);        MySqlTest.saveTestResult(label, result);    }}复制代码

下面是一个针对其中某个功能的性能测试用例(测试用例分两种,一类是HTTP单次请求的,我才用了获取请求的HttpRequestBase对象然后去重新发送并发请求,一类是多接口或者非HTTP请求,如dubbo,mysql,redis,消息队列等等,直接调用的方法进行压测):

简单HTTP请求:

class CancelReason extends OkayBase{    public static void main(String[] args) {        def argsUtil = new ArgsUtil(args)        def thread = argsUtil.getIntOrdefault(0, 2)        def times = argsUtil.getIntOrdefault(1, 5)        def base = getBase()        Headgear drive = new Headgear(base);        drive.getAllHeadgear()        def request = FanLibrary.getLastRequest()        def timesthread = new RequestThreadTimes(request, times)        new Concurrent(timesthread, thread,"获取所有头套,内容流转二期压测接口").start()        allOver()    }}复制代码

非简单HTTP请求的请参考之前写过的性能测试框架Demo:​​性能测试框架第二版​​。这类方法写起来比较简单,使用范围很高,但是需要根据不同的业务需求解决多线程数据和对象的安全问题。

整个项目放在git上,功能测试在本地,自动化项目和性能项目在服务器,采用Groovy脚本运行,也可以在本地调试。自动化项目采取定时或者间隔固定时间自动运行,性能项目收到输入命令​​groovy filename.groovy​​来运行。