4.5 nodejs自动化测试设计思路2

1、在上文中采用了数据、case、测试代码分离的方式设计,但是在实际操作中还有点问题,并且还有很大的优化空间,首先就是参数引用的问题,在上文中,没有对提取的参数作别名处理,所以提取到了重名的参数会覆盖掉之前的,现修正如下

config/case/task_case.js

const pathList = require('../../config/global/path')
const data = require('../data/task')
/**
 * @description isQuote:true,为true时,说明引用了提取的字段,引用字段要和提取字段名称一致,且引用字段名称前面需要加$符号
 * @description isExtract:1 提取reqest,2提取response,3 提取request和response
 * @description as:别名
 */

exports.task = [
    {
        isExtract: 2,
        name: 'keyword',
        config: {
            url: pathList.keywordPathList.save,
            method: 'post',
            headers: {},
            data: data.keyword
        },
        assert: [{code: '0000'}, {msg: '执行成功'}],
        res_extract: ['data'],
        as: {
            data: 'id'
        }
    },
    {
        isQuote: true,
        isExtract: 3,
        name: 'save',
        config: {
            url: pathList.taskList.save,
            method: 'post',
            headers: {},
            data: data.save
        },
        assert: [{code: '0000'}, {msg: '一切ok'}],
        res_extract: ['data'],
        req_extract: ['spiderName']
    },
    {
        isQuote: true,
        name: 'edit',
        config: {
            url: pathList.taskList.save + '/' + '{data}',
            method: 'put',
            headers: {},
            data: data.edit
        },
        assert: [{code: '0000'}, {msg: '一切ok'}, {data: '修改任务完成'}]
    },
    {
        isQuote: true,
        name: 'get',
        config: {
            url: pathList.taskList.save,
            method: 'get',
            headers: {},
            params: {
                spiderName: '{spiderName}',
                page: 1,
                pageSize: 10
            },
        },
        assert: [{msg: '一切ok'}, {totalCount: 1}]
    },
    {
        isQuote: true,
        name: 'reset',
        config: {
            url: pathList.taskList.reset + '/' + '{data}',
            method: 'post',
            headers: {},
        },
        assert: [{code: '0000'}, {msg: '一切ok'}]
    },
    {
        isQuote: true,
        name: 'run',
        config: {
            url: pathList.taskList.run + '/' + '{data}',
            method: 'get',
            headers: {},
            params: {
                taskName: '{spiderName}'
            }
        },
        assert: [{code: '0000'}, {msg: '一切ok'}]
    }

]


看case中有个as字段,是为了给提取重名的字段时,避免被替换掉

2、完成这个功能,我重新对方法进行了修改

utils/regexp.js

const type_judge = require('../utils/type_judge');
const assert = require('assert')

/**
 * @description 根据正则表达式提取字符串中的数据
 * @param {string} str 要提取的字符串,case中需要提取的值
 * @param {object|string} obj 待提取的对象或者字符串,response或者request
 * @return {array} 被提取的值会以数组形式返回
 */
function extract(str, obj) {
    let string_pattern = `(?<="${str}":").+?(?=")`;
    let number_pattern = `(?<="${str}":)\\d+`;
    let arr;
    if (type_judge(obj) === 'String') {
        arr = obj.match(new RegExp(string_pattern, 'gm')) || null
        if (arr === null) {
            arr = obj.match(new RegExp(number_pattern, 'gm')) || null
        }
    } else if (type_judge(obj) === 'Object') {
        arr = JSON.stringify(obj).match(new RegExp(string_pattern, 'gm')) || null;
        if (arr === null) {
            arr = JSON.stringify(obj).match(new RegExp(number_pattern, 'gm')) || null;
        }
    } else {
        assert.fail('type of parms(obj) is not correct')
    }
    return arr
}

/**
 * @description 根据正则表达式保存提取的数据
 * @param {array}array case中的需要提取值的数组字段,如
 * @param {object}obj response或者request
 * @param {*}args 可选参数,用来传递别名
 * @return {object}返回所有从对象中提取的数据
 */
function saveExtract(array, obj, ...args) {
    let field = {}
    if (array !== [] && array !== undefined) {
        for (let i in array) {
            let arr = extract(array[i], obj);
            if (arr !== null) {
                for (let j in arr) {
                    if (args.length !== 0 && args[0] !== undefined) {
                        for (let n in args[0]) {
                            if (n === array[i]) {
                                field[args[0][n]] = arr[j]
                            }
                        }
                    } else
                        field[array[i]] = arr[j]
                }
            } else
                break
        }
    }
    return field
}

/**
 *
 * @param {object}obja case中需要提取的数组
 * @param {object}objb request,即response.config.data
 * @param {object}objc response
 * @param {*}args 可选参数,传递case中的别名
 * @return {object}根据isExtract的值,提取对应的对象的值
 */
function excute(obja, objb, objc, ...args) {
    let temp = {};
    if (obja['isExtract'] && args.length !== 0 && args[0] !== undefined) {
        switch (obja['isExtract']) {
            case 1:
                temp = saveExtract(obja['req_extract'], objb, args[0]);
                break;
            case 2:
                temp = saveExtract(obja['res_extract'], objc, args[0]);
                break;
            case 3:
                temp = Object.assign(saveExtract(obja['req_extract'], objb, args[0]), saveExtract(obja['res_extract'], objc, args[0]));
                break;
            default:
                break
        }
    } else if (obja['isExtract'] && (args.length === 0 || args[0] === undefined)) {
        switch (obja['isExtract']) {
            case 1:
                temp = saveExtract(obja['req_extract'], objb);
                break;
            case 2:
                temp = saveExtract(obja['res_extract'], objc);
                break;
            case 3:
                temp = Object.assign(saveExtract(obja['req_extract'], objb), saveExtract(obja['res_extract'], objc));
                break;
            default:
                break
        }
    }
    return temp
}

module.exports = excute

utils/replace_config.js

/**
 * @description 正则匹配并替换引用
 * @param {object}obj
 * @param {object}field
 * @return {object}返回替换后的对象||原对象
 */
function rep(obj, field) {
    if (obj['isQuote']) {
        let temp = JSON.stringify(obj)
        for (let i in Object.keys(field)) {
            let reg = new RegExp(`\{(${Object.keys(field)[i]})\}`, 'gm')
            temp = temp.replace(reg, field[Object.keys(field)[i]])
        }
        let result = JSON.parse(temp)
        // result['config']['url'] = encodeURI(result['config']['url'])
        return result
    } else {
        return obj
    }
}

module.exports = rep


3、如上就是新修正的方法,但是这种并不是最终的方式,还可以进一步优化,使用动态加载的策略来设计,这边只简单了写个示例

utils/read_dir.js

const fs = require('fs');

function readdirSync(path){
    return fs.readdirSync(path)
}

module.exports = readdirSync

case/test/test_case.js

module.exports = [
    {name: 'test_1'},
    {name: 'test_2'},
    {name: 'test_3'},
]

case/test/test1_case.js

module.exports = [
    {name: 'test1_1'},
    {name: 'test1_2'},
    {name: 'test1_3'},
]

nodejs导出使用exports导出时,是导出一个对象,使用module.exports导出时,会根据赋值的类型进行导出,切记

api/list/dynamic_test.js

const read = require('../../utils/read_dir')
const path = require('path')
const assert = require('assert')
let list = read(path.resolve('src/config/test'))
for(let i in list){
    let config = require(`../../config/test/${list[i]}`)
    describe(`${list[i]}`,function (){
        for (let j in config)
        it(`${config[j].name}`,function (){
            assert.ok('success')
        })
    })
}

这样设计的话,那么无论是修改接口,还是新增功能,用户只用直接在case目录下新建一个case,然后按照case格式去添加参数即可,不需要在动任何的逻辑代码,这种设计的方式,个人认为会更合理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值