• 【测试沉思录】13. 玩转 Dubbo 接口测试的 3 种姿势


    欢迎订阅我的新专栏《现代命令行工具指南》,精讲目前最流行的开源命令行工具,大大提升你的工作效率。

    作者:王伟 编辑:毕小烦

    微服务盛行的今天,保障服务质量至关重要,作为测试人员,如何测试 Dubbo 接口呢?本文系统梳理了几种常见的测试方法,希望对大家有所启发。

    Dubbo 简介

    随着互联网行业的蓬勃发展和业务规模的持续增长,网站应用的规模也在不断扩大,同时也推动着互联网技术架构的持续演进:单一应用架构 -> 垂直应用架构 -> 分布式服务架构 -> 流动计算架构

    如下图所示:

    img

    技术架构从 All in one 的大而全逐步演化为服务独立的小而精,服务数量越来越多,服务间的调用和依赖关系也越来越复杂,用于提升服务质量的 SOAService-Oriented Architecture,面向服务的架构) 自然就出现了,SOA 将单一进程的应用做了拆分,形成独立对外提供服务的组件,每个组件通过网络协议对外提供服务。

    服务化架构继续演进,形成了更加细粒度的微服务架构(Microservices Architecture Pattern)。在微服务架构中,一个应用会被拆分为一个个独立、可配置、可运行、可维护的子服务,极大的方便了服务的复用,不同服务的组合也能够快速响应新的业务逻辑。

    同时,随着敏捷开发、持续支付、DevOps 的发展与实践,以及 Docker 和 K8S 等容器化技术和平台的成熟,微服务架构已然流行起来。

    Dubbo 正是微服务开发框架中的佼佼者。

    Dubbo 是什么

    官网上是这样介绍的:

    Dubbo 是一款微服务开发框架,它提供了 RPC 通信微服务治理 两大关键能力。

    这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。

    同样,来自 Dubbo 官方的架构图如下所示:

    img

    先提供服务,再消费服务,Dubbo 接口测试的逻辑都在这张图上了。

    接下来进入正题,看看 Dubbo 要测什么?

    Dubbo 要测什么

    不同应用之间通过 RPC 协议提供服务(Service 接口),而这些服务就是我们要测的内容。

    下图是经典的测试金字塔:

    img

    图来自网络

    从 ROI 来讲,自下而上效率越来越慢,成本则越来越高。从重要性来讲,服务这一层是核心,我们不仅要保障单个系统的输入输出没有问题,还要保障各系统的集成和交互没有问题。

    那 RPC 是什么?

    维基百科:

    在分布式计算中,RPC(Remote Procedure Call,远程过程调用)是一个计算机通信协议。

    该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。

    RPC 是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求 - 接受回应进行信息交互的系统。

    通俗的讲:

    RPC 是指远程过程调用,也就是说两台服务器 A,B,一个应用部署在 A 服务器上,想要调用 B 服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

    在具备了一些基础知识之后,接下来就可以看如何测试了。

    Dubbo 要怎么测

    测试 Dubbo 接口大致可分为三种姿势(方式):敲命令、写代码和用工具,每种姿势都有其适用的场景。

    如下图所示:

    img

    下面我们先准备好被测服务。

    做好准备:提供服务

    既然要测试(消费)服务,首先得提供服务。

    假设要测试的服务关键信息如下:

    • Dubbo 版本:2.7.12
    • 服务的应用名:demo-provider
    • 服务的端口(默认):20880
    • 服务的注册地址:zookeeper://127.0.0.1:2181
    • 被测接口的全限定名:org.apache.dubbo.samples.provider.DemoService
    • 接口的分组:略
    • 接口的版本:略

    要测试的接口名为 DemoService,这里有几种典型的方法:

    public interface DemoService {
    
        // 一个简单的参数
        String singleParamMethod(String name);
        
        // 多个参数
        String multiParamMethod(String name, List<String> topics);
    
        // 参数是一个 JavaBean 对象
        String beanParamMethod(Info info);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    DemoService 中用到的 JavaBean 对象:

    public class Info implements Serializable {
        private String name;
        private int age;
        private String address;
        
        // get、set 略
        
        public Info() {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    本例是在 dubbo-samples-api 的基础上修改的。

    在确保 ZooKeeper 启动成功,且被测服务也启动成功之后,就可以进入测试环节了。

    第 1 种姿势:敲命令

    Telnet

    Telnet 是什么?

    Telnet 协议是 Internet 远程登录服务的标准协议和主要方式,它为用户提供了在本地计算机上远程管理主机的能力。

    Telnet 常用命令:

    # Telnet 到主机的默认端口
    $ telnet host
    
    # Telnet 到主机的指定端口
    $ telnet ip_address port
    
    # 退出 Telnet 会话
    $ quit
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Dubbo 从 2.0.5 版本开始支持通过 telnet 命令来进行服务治理,但不同版本稍有区别。

    对于使用 Telnet 而言, Dubbo 2.7.13 是一个分界线,之前使用 telnet IP PORT连接到 Dubbo 协议端口(默认是 20880),之后连接到 QOS 端口(默认是 22222),命令的使用大致相同。

    以 Dubbo 2.7.12 为例:

    # 连接到 dubbo 
    $ telnet localhost 20880
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    
    # 查看都支持哪些命令
    dubbo>help
    Please input "help [command]" show detail.
     cd [service]                     - Change default service.
     clear [lines]                    - Clear screen.
     count [service] [method] [times] - Count the service.
     pwd                              - Print working default service.
     exit                             - Exit the telnet.
     help [command]                   - Show help.
     invoke [service.]method(args)    - Invoke the service method.
     ls [-l] [service]                - List services and methods.
     log level                        - Change log level or show log
     ps [-l] [port]                   - Print server ports and connections.
     select [index]                   - Select the index of the method you want to invoke.
     shutdown [-t <milliseconds>]     - Shutdown Dubbo Application.
     status [-l]                      - Show status.
     trace [service] [method] [times] - Trace the service.
    
    # 查看服务的接口列表
    dubbo>ls
    PROVIDER:
    org.apache.dubbo.samples.api.DemoService
    
    # 查看指定接口的方法列表
    dubbo>ls org.apache.dubbo.samples.api.DemoService
    org.apache.dubbo.samples.api.DemoService (as provider):
    	multiParamMethod
    	beanParamMethod
    	singleParamMethod
    
    # 切到指定(默认)接口
    dubbo>cd org.apache.dubbo.samples.api.DemoService
    Used the org.apache.dubbo.samples.api.DemoService as default.
    You can cancel default service by command: cd /
    
    # 可直接调用这个接口的方法
    dubbo>invoke singleParamMethod("testingweekly")
    Use default service org.apache.dubbo.samples.api.DemoService.
    result: "Name: testingweekly"
    elapsed: 2 ms.
    
    
    # 如果不切换到指定接口,也可以这样使用全路径调用接口的方法:
    # invoke org.apache.dubbo.samples.api.DemoService.singleParamMethod("testingweekly")
    # invoke org.apache.dubbo.samples.api.DemoService.multiParamMethod("testingweekly",["tools","articles"])
    # invoke org.apache.dubbo.samples.api.DemoService.beanParamMethod({"name": "testingweekly","age": 2,"address": "https://www.yuque.com/bxiaofan/testingweekly"})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    注意:

    • macOS 需要安装 telnet 命令:brew install telnet
    • macOS 连接到 dubbo 服务之后,如果粘贴的内容有中文,会断开连接,所以我在例子中都改成了英文。

    更多 Telnet 的用法:

    • https://dubbo.apache.org/zh/docs/v3.0/references/telnet/
    • https://dubbo.apache.org/zh/docs/v3.0/references/qos/

    第 2 种姿势:写代码

    写代码测试 Dubbo 接口得搭建一个测试项目,可以使用 https://spring.io/quickstart 快速搭建一个 Spring Boot 项目。

    写代码也分两种方式:直接引用和泛化调用。

    直接引用

    直接引用 Dubbo 的方式需要依赖被测服务的 JAR 包,然后就可以跟写单元测试一样写 Dubbo 接口的测试用例了。

    STEP 1. 在 pom.xml 中添加关键依赖:

     
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-testartifactId>
        <version>4.2.5.RELEASEversion>
    dependency>
    
    <dependency>
        <groupId>org.apache.dubbogroupId>
        <artifactId>dubboartifactId>
        <version>2.7.12version>
    dependency>
    
    <dependency>
        <groupId>org.apache.curatorgroupId>
        <artifactId>curator-frameworkartifactId>
        <version>4.2.0version>
    dependency>
    <dependency>
        <groupId>org.apache.curatorgroupId>
        <artifactId>curator-recipesartifactId>
        <version>4.2.0version>
    dependency>
    
    <dependency>
        <groupId>org.testnggroupId>
        <artifactId>testngartifactId>
        <version>6.14.3version>
        <scope>testscope>
    dependency>
    
    <dependency>
        <groupId>***groupId>
        <artifactId>demo-poviderartifactId>
        <version>*.*.*-SNAPSHOTversion>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    注意:

    如果是本地搭建的服务,也可以将被测服务的 JAR 包直接导入测试项目。

    STEP 2. 在 resources 下新建一个 XML 文件,用于配置服务提供者的信息。

    假设文件名是:dubbo-consumer.xml

    配置的内容如下:

    
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    
        
        <dubbo:application name="demo-provider"/>
    
        
        <dubbo:registry address="zookeeper://127.0.0.1:2181" timeout="60000" check="false"/>
    
        
        <dubbo:reference id="demoService"
                         interface="org.apache.dubbo.samples.api.DemoService"
                         timeout="10000" check="false"/>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Tips:

    更多配置可参考:https://dubbo.apache.org/zh/docs/references/configuration/xml/

    STEP 3. 编写测试用例

    @ContextConfiguration(locations = "classpath:dubbo-consumer.xml")
    public class DirectRefTest extends AbstractTestNGSpringContextTests {
    
        @Autowired
        private DemoService demoService;
    
        @Test
        public void singleParamMethodTest() {
    
            String result = demoService.singleParamMethod("软件测试周刊");
    
             System.out.println(result);
        }
    
        @Test
        public void multiParamMethodTest() {
            List<String> list = new ArrayList<String>();
            list.add("测试周刊");
            list.add("测试工具");
            String result = demoService.multiParamMethod("软件测试周刊", list);
    
             System.out.println(result);
        }
        
        @Test
        public void multiParamMethodTest() {
    
            List<String> list = new ArrayList<String>();
            list.add("测试周刊");
            list.add("测试工具");
            String result = demoService.multiParamMethod("软件测试周刊", list);
    
            System.out.println(result);
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    直接引用的方式来测试 Dubbo 接口,需要依赖被测服务的 JAR 包,还要配置 XML,这些都很麻烦。比较方便的是写测试用例的时候可直接查看源码来获取所需的信息。

    泛化调用

    Dubbo 提供了泛化调用,当我们想调用 Dubbo 服务时,无需依赖相关 JAR 包,只要知道一个接口全限定名以及入参返参,就能调用到该服务。这就大大降低了服务提供者和消费者的耦合性。

    很多 Dubbo 接口测试框架和平台就是基于此开发的。

    Dubbo 官网是这样说的:

    泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过 GenericService 调用所有服务实现。

    更多请看:https://dubbo.apache.org/zh/docs/advanced/generic-reference/

    Dubbo 泛化调用具体应该怎么用呢?

    测试用例如下:

    public class GenericTest {
    
        @Test
        public void testDemoService() {
            // 1.引用远程服务
            ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
    
            // 2. 设置服务提供者的应用名
            reference.setApplication(new ApplicationConfig("demo-provider"));
            // 3. 设置注册中心地址
            reference.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
            // 4. 设置要测试的接口信息
    
            // 接口名
            reference.setInterface("org.apache.dubbo.samples.api.DemoService");
            // 及其他信息
            // reference.setVersion("");
            // reference.setGroup("");
    
            // 5. 将其声明为泛化接口
            reference.setGeneric(true);
    
    
            // 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用
            GenericService genericService = reference.get();
    
            List<String> topics = new ArrayList<String>();
            topics.add("测试周刊");
            topics.add("测试工具");
            topics.add("谁在招测试?");
    
            // 泛化调用的方法:
            //  $invoke(String method, String[] parameterTypes, Object[] args)
            //  $invoke(String 方法名, String[] 方法的参数类型, Object[] 传给这个接口的参数)
    
            // 例1:调用一个简单的单类型方法
            Object result1 = genericService.$invoke("singleParamMethod", new String[]{"java.lang.String"}, new Object[]{"软件测试周刊"});
    
            // 例2:调用一个多参数的方法
    //        Object result2 = genericService.$invoke("testMethod2", new String[]{"java.lang.String", "java.util.List"}, new Object[]{"李四", Collections.singleton("杭州")});
            Object result2 = genericService.$invoke("multiParamMethod", new String[]{"java.lang.String", "java.util.List"}, new Object[]{"软件测试周刊",topics});
    
            // 例3:调用一个参数是 Java Bean 的方法
            Map<String, Object> info = new HashMap<>();
            info.put("name", "软件测试周刊");
            info.put("age", 2);
            info.put("address", "https://www.yuque.com/bxiaofan/testingweekly");
    
            Object result3 = genericService.$invoke("beanParamMethod", new String[]{"org.apache.dubbo.samples.api.DemoService$Info"}, new Object[]{info});
    
            System.out.println(result1);
            System.out.println(result2);
            System.out.println(result3);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    第 3 种姿势:用工具

    JMeter

    JMeter 本身并不支持 Dubbo 接口的测试,需要依赖一个第三方插件:jmeter-plugins-for-apache-dubbo

    在演示如何测试之前,得先准备好环境。

    STEP 1. 下载 JMeter

    下载地址:https://jmeter.apache.org/download_jmeter.cgi ,我用的是最新的 Apache JMeter 5.5 版本。

    STEP 2. 下载第三方插件

    下载地址:https://github.com/thubbo/jmeter-plugins-for-apache-dubbo,名称为: jmeter-plugins-dubbo-2.7.8-jar-with-dependencies.jar

    STEP 3. 安装第三方插件

    1. jmeter-plugins-dubbo-2.7.8-jar-with-dependencies.jar 放到 apache-jmeter-5.5/lib/ext/ 下面。
    2. 重启 JMeter。

    至此准备工作完毕。

    怎么用呢?

    STEP 1. 在「测试计划」上添加「线程组」

    STEP 2. 在「线程组」上添加「Dubbo Sample」

    如下图所示:

    img

    STEP 3. 配置 Dubbo Sample

    ① 测试一个简单的单类型方法:

    img

    说明:

    • Registry Center:注册中心用的是 zookeeper,注册地址(Address)是:127.0.0.1:2181。超时时间(Timeout)为 6000 ms;

    • RPC Protocol: dubbo:// (默认);

    • Interface:点 「Get Provider List」可以获取被测服务的接口列表和方法列表,下面的 Interface 和 Method 通过选择就可以了,不必再手动输入;

    • Args:

      • paramType:参数类型,分为简单数据类型和自定义数据类型。
      • **paramValue:**参数的值,基本类型和包装类型直接使用具体的值,自定义类型与 List 或者 Map 等使用 JSON 格式数据。

    关于参数类型:

    • 简单数据类型:填写基本类型/基本类型包装类/引用类型,如,【“int”, “double”, “java.lang.Integer”, “java.lang.Double”, “java.lang.String”,“java.util.List”, “java.util.Map”】。
    • 自定义数据类型:填写类的完整路径,如,【org.apache.dubbo.samples.api.Info】。
    • 类型对照表:https://github.com/thubbo/jmeter-plugins-for-apache-dubbo/wiki/ParameterComparisonTable
    • 复杂参数案例:https://github.com/thubbo/jmeter-plugins-for-apache-dubbo/wiki/FAQ

    ② 测试一个多参数的方法:

    img

    ③ 测试一个参数为 Java Bean 的方法:

    img

    STEP 4. 添加「监听器」-> 查看结果树

    执行后的结果如下:

    img

    Postman

    我们无法直接使用 Postman 测试 Dubbo 接口,但可以自己开发一个接口服务,接收 Postman 传过来的 Dubbo 接口信息,然后通过泛化调用的方式调用相应的 Dubbo 接口,再把结果返回给 Postman 进行验证。

    如下所示:

    img

    这种方式具有普适性,缺点就是会牺牲一些测试效率。

    使用时是这样的:

    img

    总结

    本文介绍了测试 Dubbo 接口的三种姿势:敲命令、写代码和用工具,每种姿势又有多种不同的使用方式,其中泛化调用被广泛应用于各种 Dubbo 测试工具、框架和平台之中,需重点掌握。当然,也有一些测试框架使用命令行(Telnet)的方式,不必细究。

    有句话叫存在即合理,每种姿势都有其适用的场景,并没有绝对的好坏之分,我们在实际的测试过程中,也是要按需选用。

    那么,你平时都在使用什么样的方式测试 Dubbo 接口呢?请留言告诉我。

    参考资料

    • 《深入理解apache dubbo与实战》
    • https://dubbo.apache.org/zh/

    (完)

    如果文章对你有帮助,记得留言、点赞、加关注哦!

  • 相关阅读:
    spring框架
    HTML语义化标签(一)
    多 Activity 多 Page 的 UI 架构
    MySQL的事务隔离是如何实现的?
    Fundamental Library for ABAP 主要的组成部分概述
    软件工程知识总结梳理
    JG/T 357-2012 木丝水泥板检测
    mycat实现分库分表小例子
    net基于asp.net的二手商品的交易系统-二手网站-计算机毕业设计
    OJ练习第167题——单词接龙
  • 原文地址:https://blog.csdn.net/wirelessqa/article/details/127737608