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

Posted 毕小烦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了测试沉思录13. 玩转 Dubbo 接口测试的 3 种姿势相关的知识,希望对你有一定的参考价值。

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

作者:王伟 编辑:毕小烦

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

Dubbo 简介

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

如下图所示:

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

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

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

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

Dubbo 是什么

官网上是这样介绍的:

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

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

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

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

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

Dubbo 要测什么

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

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

图来自网络

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

那 RPC 是什么?

维基百科:

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

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

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

通俗的讲:

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

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

Dubbo 要怎么测

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

如下图所示:

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

做好准备:提供服务

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

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

  • 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);


DemoService 中用到的 JavaBean 对象:

public class Info implements Serializable 
    private String name;
    private int age;
    private String address;
    
    // get、set 略
    
    public Info() 

    

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

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

第 1 种姿势:敲命令

Telnet

Telnet 是什么?

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

Telnet 常用命令:

# Telnet 到主机的默认端口
$ telnet host

# Telnet 到主机的指定端口
$ telnet ip_address port

# 退出 Telnet 会话
$ quit

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")

注意:

  • 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 中添加关键依赖:

 <!-- Spring单元测试依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.5.RELEASE</version>
</dependency>
<!-- dubbo-->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.7.12</version>
</dependency>
<!-- ZooKeeper -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.2.0</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.2.0</version>
</dependency>
<!-- testNG -->
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.14.3</version>
    <scope>test</scope>
</dependency>
<!-- 你要测试的服务提供者(Provider):按实际信息修改 -->
<dependency>
    <groupId>***</groupId>
    <artifactId>demo-povider</artifactId>
    <version>*.*.*-SNAPSHOT</version>
</dependency>

注意:

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

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

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

配置的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<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>

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);
    
    

直接引用的方式来测试 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);

    

第 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」

如下图所示:

STEP 3. 配置 Dubbo Sample

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

说明:

  • 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

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

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

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

执行后的结果如下:

Postman

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

如下所示:

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

使用时是这样的:

总结

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

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

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

参考资料

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

(完)

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

以上是关于测试沉思录13. 玩转 Dubbo 接口测试的 3 种姿势的主要内容,如果未能解决你的问题,请参考以下文章

测试沉思录10. 我们用到的3种Mock测试方案

测试沉思录10. 我们用到的3种Mock测试方案

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(13)-Charles如何进行Mock和接口测试

测试沉思录6. 设计一款简单的接口自动化测试框架

测试沉思录6. 设计一款简单的接口自动化测试框架

测试沉思录23. 如何实现基于场景的接口自动化测试用例?