zoukankan      html  css  js  c++  java
  • 基于Groovy+HttpRestful的超轻量级的接口测试用例配置的设计方案及DEMO实现

    目标###

    设计一个轻量级测试用例框架,接口测试编写者只需要编写测试用例相关的内容(入参及结果校验),不需要理会系统的实现,不需要写跟测试校验无关的内容。

    思路###

    测试用例分析####

    一个用例由以下部分组成:

    (1) 测试用例名称 ; (2) 接口名及URL/Path; (3) 接口入参; (4) 接口返回结果校验。

    测试框架需要读取用例配置信息,根据指定接口及入参调用服务,并根据指定校验函数来对接口返回结果做检验,判断测试用例是否执行成功。

    设计考量####

    为了灵活调用不同接口,针对以上的配置,(2) 采用 http restful 的方式; (3) 采用 Map ; (4) 需要一套校验语法。这里暂时直接采用 groovy 脚本。

    DEMO实现###

    使用者需要做什么####

    接口测试用例编写者只需要定义一个 TestCase 类即可。这个类含有如下信息:

    (1) 待测试接口的 url : http://ip:7001 及 restful 路径 /xxx

    (2) 带有 @Case 注解的方法。 里面返回一个 Map,

    name: 测试用例名 ;

    param: 入参map ;

    check: 校验函数。 data 就是返回的顶层。

    比如搜索测试用例类SearchTestCases:

    package cc.lovesq.study.testcase.qa
    
    import cc.lovesq.study.testcase.Case
    
    class SearchTestCases {
    
        def url = 'http://ip:7001'
        def path = '/searchApp/order/search'
    
        @Case
        def get() {
            return [
               'name': 'testSearchOrderNo',
               'param': ['shopId': 55, 'orderNo': 'E20180507200552032000001', 'source':'service-test'],
               'check': { data ->
                   data.list.each {
                       order ->
                           order.orderNo == 'E20180507200552032000001'
                   }
               }
            ]
        }
    
    }
    
    

    详情测试用例类

    package cc.lovesq.study.testcase.qa
    
    import cc.lovesq.study.testcase.Case
    
    class DetailTestCases {
    
        def url = 'http://ip:7001'
        def path = '/detailApp/orderInfo/byOrderNo'
    
        @Case
        def get() {
            return [
               'name': 'testSingleOrderDetail',
               'param': ['shopId': 55, 'orderNo': 'E20180507200552032000001', 'source':'service-test', 'bizGroup': 'trade'],
               'check': { data ->
                   data.mainOrderInfo.orderNo == 'E20180507200552032000001'
               }
            ]
        }
    
    }
    
    

    框架基本实现####

    通过指定的 TestCase 类,读取其用例配置信息,识别其中的用例配置,通过Http调用接口,然后回调指定的校验函数来校验结果。

    package cc.lovesq.study.testcase
    
    import groovyx.net.http.ContentType
    import groovyx.net.http.HTTPBuilder
    import org.slf4j.Logger
    import org.slf4j.LoggerFactory
    
    import static groovyx.net.http.Method.POST
    
    class CaseExecutor {
    
        static Logger log = LoggerFactory.getLogger(CaseExecutor.class)
    
        def invokeAllCases(testCase) {
            Object tc = testCase
            tc.getClass().getDeclaredMethods().findAll {
    
                // 识别测试用例: 带有 @Case
                it.getAnnotation(Case.class) != null
    
            }.each {
                it ->
                    def caseInfo = it.invoke(tc, null)
                    def result = exec(caseInfo['name'], tc.url, tc.path, caseInfo['param'], caseInfo['check'])
                    println("case=${caseInfo['name']}, result=${result}")
            }
        }
    
        def exec(name, url, path, param, check) {
    
            def http = new HTTPBuilder(url)
    
            def result
    
            http.request(POST) {
                uri.path = path
                requestContentType = ContentType.JSON
                body = param
    
                response.success = { resp, json ->
                    def data = json.data.data
                    try {
                        log.info("Enter Test Case : {}", name)
                        check(data)
                        result = "success"
                    } catch (Throwable e) {
                        result = "failed"
                    } finally {
                        log.info("Exit Test Case : {}", name)
                    }
                }
                response.failure = { resp ->
                    println "Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
                    def errorInfo = """
                        Call error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}
                        Name: ${name}
                        Url: ${url}
                        Path: ${path}
                        Param: ${param}
                    """
                    log.warn(errorInfo)
                    result = "failed"
                }
            }
            result
        }
    }
    
    

    客户端运行测试用例集合:

    package cc.lovesq.study.testcase
    
    import cc.lovesq.study.testcase.qa.DetailTestCases
    import cc.lovesq.study.testcase.qa.SearchTestCases
    
    class ClientTest {
    
        def static main(args) {
    
            CaseExecutor caseExecutor = new CaseExecutor()
    
            caseExecutor.invokeAllCases(new SearchTestCases())
            caseExecutor.invokeAllCases(new DetailTestCases())
    
        }
    }
    

    代码讲解###

    • 使用了HttpBuilder 类来发送HTTP请求。需要添加POM配置:
    <dependency>
          <groupId>org.codehaus.groovy.modules.http-builder</groupId>
          <artifactId>http-builder</artifactId>
          <version>0.6</version>
    </dependency>
    
    • 使用注解 @Case 来表示测试用例。注解可以用于标识一类对象。

    • 使用Groovy闭包来传递校验逻辑。闭包可以用来传递变化的逻辑。


    自动加载用例集合###

    实际应用中,往往不会直接 new 一个 XXXTestCases 对象,而是将这些对象标记为 Component 后,在应用启动时加载这些 TestCases,建立映射。只要对 CaseExecutor 做一些扩展即可。 如下代码所示:

    @Component("caseExecutor")
    class CaseExecutor implements ApplicationContextAware {
    
        static Logger log = LoggerFactory.getLogger(CaseExecutor.class)
    
        ApplicationContext context
    
        def casePathMap = [:]
    
        @PostConstruct
        def init() {
            Map<String, Object> components = context.getBeansWithAnnotation(Component.class)
            log.info("{}", components)
            components.each {
                name, comp ->
                    try {
                        def property = comp.metaClass.getProperty(comp, 'path')
                        if ( property) {
                            casePathMap[property] = comp
                        }
                    } catch (e) {
                        log.warn("not having restPath, omit")
                    }
    
            }
        }
    
       // other codes
    
        @Override
        void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.context = applicationContext
        }
    }
    

    小结###

    本文讲解了一种基于Groovy+HttpRestful的超轻量级的接口测试用例配置的设计方案及DEMO实现。基于这种方法,可以配置化地快速增加指定服务接口的测试用例集合,而不需要额外编写冗余的测试代码。

  • 相关阅读:
    201771010134杨其菊《面向对象程序设计(java)》第十三周学习总结
    201771010107-冯志霞 实验四 软件项目案例分析
    201771010107-冯志霞 实验三 结对项目——《西北师范大学疫情防控信息系统》项目报告
    201771010107-冯志霞 实验二 个人项目-《西北师范大学学生疫情上报系统》项目报告
    201771010107 冯志霞 实验一 软件工程准备
    冯志霞201771010107《面向对象程序设计(java)》第十八周学习总结
    冯志霞201771010107《面向对象程序设计(java)》第十七周学习总结
    冯志霞201771010107《面向对象程序设计(java)》第十六周学习总结
    冯志霞201771010107《面向对象程序设计(java)》第十五周学习总结
    冯志霞201771010107《面向对象程序设计(java)》第十四周学习总结
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/9806293.html
Copyright © 2011-2022 走看看