IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 接口自动化框架脚手架-利用反射机制实现接口统一发起端 -> 正文阅读

[系统运维]接口自动化框架脚手架-利用反射机制实现接口统一发起端

持续坚持原创输出,点击蓝字关注我吧

作者:软件质量保障
知乎:https://www.zhihu.com/people/iloverain1024

接口自动化框架的归途是平台化、页面可操作化,而非少数懂代码的测试同学使用的。因此,前端就需要一个统一的接口调用服务,将需要调用的服务转发给后端,真正触发用户发起的服务。

?一、概述

在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为反射机制。

特别是在设计或运行中添加新类时,能够快速地应用开发工具动态地查询新添加类的能力。反射机制可以用来:

  • 在运行时分析类的能力。

  • 在运行时查看对象,例如,编写一个toString方法供所有类使用。

  • 实现通用的数组操作代码。

使用 Java 反射,只需要引入JDK内置的java.lang.reflect包中的类,不用引入额外的Maven配置。

二、开胃菜

先看一个非常简单的示例,该示例在运行时检查一个简单Java对象的属性。先创建一个简单的Person类,它只有name和age属性,没有方法。Person 类如下:

public class Person {         private String name;         private int age; }

下面的代码使用 Java 反射来获取这个类的所有属性。先实例化一个Person对象并使用 Object 作为声明类型:

private static List<String> getFieldNames(Field[] fields) {    List<String> fieldNames = new ArrayList<>();    for (Field field : fields)      fieldNames.add(field.getName());    return fieldNames;}?@Testpublic void givenObject_whenGetsFieldNamesAtRuntime_thenCorrect() {    Object person = new Person();    Field[] fields = person.getClass().getDeclaredFields();?    List<String> actualFieldNames = getFieldNames(fields);?    assertTrue(Arrays.asList("name", "age")      .containsAll(actualFieldNames));}

通过这个测试case,我们能够从person对象中获取一个属性对象数组,即使对对象的引用是该对象的父类型(Object)。

三、探寻类

在本节中,我们将探讨 Java 反射 API 的基础用法。通过测试case熟悉如何利用反射API获取对象的信息,例如对象的类名、修饰符、属性、方法、实现的接口等。

3.1 项目准备

以动物为对象,先定义动物吃的行为接口,该接口定义了Animal对象的进食行为。然后让我们创建一个实现Eating接口的抽象Animal类。。

Eating接口:

public interface Eating {    String eats();}

下面是实现Eating接口的抽象类Animal实现:

public abstract class Animal implements Eating {?    public static String CATEGORY = "domestic";    private String name;?    protected abstract String getSound();?    // constructor, standard getters and setters omitted }

创建另一个名为Locomotion的接口来描述动物如何移动:

public interface Locomotion {    String getLocomotion();}

创建一个名为Goat的抽象类,它继承Animal并实现Locomotion接口。由于超类实现了Eating,因此Goat也必须实现该接口的方法:

public class Goat extends Animal implements Locomotion {?    @Override    protected String getSound() {        return "bleat";    }?    @Override    public String getLocomotion() {        return "walks";    }?    @Override    public String eats() {        return "grass";????}}

OK,万事俱备,下面使用 Java 反射来获取出现在上述类和接口中的 Java 对象的各种信息。

3.2. 类名

让我们首先从Class获取对象的名称:

@Testpublic void givenObject_whenGetsClassName_thenCorrect() {    Object goat = new Goat("goat");    Class<?> clazz = goat.getClass();?    assertEquals("Goat", clazz.getSimpleName());    assertEquals("com.baeldung.reflection.Goat", clazz.getName());    assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName());}

Class的getSimpleName方法返回对象的基本名称,而另外两个方法返回其完整类名。

如果我们只知道它的完整类名,看看能否创建一个Goat类的对象:

@Testpublic void givenClassName_whenCreatesObject_thenCorrect(){    Class<?> clazz = Class.forName("com.baeldung.reflection.Goat");?    assertEquals("Goat", clazz.getSimpleName());    assertEquals("com.baeldung.reflection.Goat", clazz.getName());    assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName()); }

我们给静态方法forName的参数应该包含类包信息,否则,我们会得到一个ClassNotFoundException。

3.3. 类修饰符

我们可以调用getModifiers方法来获取类的修饰符,该方法返回一个Integer。

java.lang.reflect.Modifier类提供静态方法来分析返回的Integer是否存在特定修饰符。

让我们看下前文定义的一些类的修饰符:

@Test    public void givenClass_whenRecognisesModifiers_thenCorrect() {        try {            Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");            Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");            int goatMods = goatClass.getModifiers();            int animalMods = animalClass.getModifiers();            assertTrue(Modifier.isPublic(goatMods));            assertTrue(Modifier.isAbstract(animalMods));            assertTrue(Modifier.isPublic(animalMods));        } catch (ClassNotFoundException e){            e.printStackTrace();        }    }

当然我们通过这种方法也能够获取项目中引入 jar 的类修饰符。

3.4. Package

我们还能够获取有关任何类或对象的包的信息,通过调用类对象的getPackage方法返回。

@Testpublic void givenClass_whenGetsPackageInfo_thenCorrect() {    Goat goat = new Goat("goat");    Class<?> goatClass = goat.getClass();    Package pkg = goatClass.getPackage();    assertEquals("com.baeldung.reflection", pkg.getName());}

3.3. 超类

在许多情况下,尤其是在使用库类或 Java 的内置类时,我们可能事先不知道我们正在使用的对象的超类。

但是我们可以通过使用Java反射来获取任何 Java 类的超类,下面代码来获取Goat的超类。

@Testpublic void givenClass_whenGetsSuperClass_thenCorrect() {    Goat goat = new Goat("goat");    String str = "any string";?    Class<?> goatClass = goat.getClass();    Class<?> goatSuperClass = goatClass.getSuperclass();?    assertEquals("Animal", goatSuperClass.getSimpleName());    assertEquals("Object", str.getClass().getSuperclass().getSimpleName());}

3.6. 实现的接口

使用 Java 反射,我们还能够获取给定类实现的接口列表。让我们获取Goat类和Animal抽象类实现的接口的类类型:

@Testpublic void givenClass_whenGetsImplementedInterfaces_thenCorrect(){    Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");    Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");?    Class<?>[] goatInterfaces = goatClass.getInterfaces();    Class<?>[] animalInterfaces = animalClass.getInterfaces();?    assertEquals(1, goatInterfaces.length);    assertEquals(1, animalInterfaces.length);    assertEquals("Locomotion", goatInterfaces[0].getSimpleName());    assertEquals("Eating", animalInterfaces[0].getSimpleName());}

从断言中注意到,每个类只实现一个接口。检查这些接口的名称,我们发现Goat实现了Locomotion和Animal实现了Eating。

我们可以发现Goat是抽象类Animal的子类,也实现了接口方法eats(),Goat其实也实现了Eating接口。

但是需要注意的是,只有类显式声明为使用implements关键字实现的那些接口才会出现在返回的数组中。

因此,即使一个类实现了接口方法(继承的父类实现了该接口方法),但其没有直接使用implements关键字声明该接口,该接口也不会出现在返回的接口数组中。

3.7. 构造函数、方法和属性

使用 Java 反射,我们还能够获取任何对象类的构造函数以及方法和属性。

private static List<String> getMethodNames(Method[] methods) {    List<String> methodNames = new ArrayList<>();    for (Method method : methods)      methodNames.add(method.getName());    return methodNames;}

让我们看看如何获取Goat类的构造函数:

@Testpublic void givenClass_whenGetsConstructor_thenCorrect(){    Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");?    Constructor<?>[] constructors = goatClass.getConstructors();?    assertEquals(1, constructors.length);    assertEquals("com.baeldung.reflection.Goat", constructors[0].getName());}

我们还可以获取Animal类的属性:

@Testpublic void givenClass_whenGetsFields_thenCorrect(){    Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");    Field[] fields = animalClass.getDeclaredFields();?    List<String> actualFields = getFieldNames(fields);?    assertEquals(2, actualFields.size());    assertTrue(actualFields.containsAll(Arrays.asList("name", "CATEGORY")));}

我们可以类似地获取Animal类的方法:

@Testpublic void givenClass_whenGetsMethods_thenCorrect(){    Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");    Method[] methods = animalClass.getDeclaredMethods();    List<String> actualMethods = getMethodNames(methods);?    assertEquals(4, actualMethods.size());    assertTrue(actualMethods.containsAll(Arrays.asList("getName",      "setName", "getSound")));}

四、在接口自动化平台中的应用

接口自动化框架的归途是平台化、页面可操作化,而非少数懂代码的测试同学使用的。因此,前端就需要一个统一的接口调用服务,将需要调用的服务转发给后端,真正触发用户发起的服务。可以参考下面的流程图。

例如美团接口自动化测试平台Lego,用户将服务名、测试method、request等内容作为输入,发起后会统一调后端的服务发起接口。

再比如淘宝开放平台,也是同样的实现方式。

https://open.taobao.com/new/apitesttool?spm=a219a.15212433.0.0.1c41669aDvRvXZ&apiName=taobao.appstore.subscribe.get

因此,接口测试平台的实现,反射机制是非常重要的。(当然有些自动化测试平台可能不是Java语言开发的,但是同样会有反射的影子

下面我就以简单的例子演示下,项目结构如下:

1.开发两个service(API)

public class CreateService {    public boolean create(String name){        if (null !=name){            System.out.println("-----create success----");            return true;        }        System.out.println("-----create failure----");        return false;    }}?public class QueryService {    public boolean query(String name){        if (null !=name){            System.out.println("-----query success----");            return true;        }        System.out.println("-----query failure----");        return false;    }}
  1. 利用反射机制实现统一接口调出服务,其入参为类名、被调方法、方法的request

public class Invoke {?    public void invokeProxy(String serviceName, String methodName, String request) {        try {            Class<?> serviceClass = Class.forName(serviceName);            Object service = serviceClass.getDeclaredConstructor().newInstance();            Method method = serviceClass.getMethod(methodName, String.class);            method.invoke(service, request);?        } catch (ClassNotFoundException e){            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        }    }
  1. 测试Invoke.invokeProxy接口

  @Test    public void testInvokeProxy(){        String serviceName = "cn.qa.reflect.demo.service.CreateService";        String request = "testName";        String methodname = "create";        invokeProxy(serviceName, methodName, request);    }
  1. 测试结果

-----create success----

ok,这就实现了一个简单的统一接口调出服务。

喜欢的话,就点个赞和在看再走吧??👍👍

- END -


下方扫码关注?软件质量保障,与质量君一起学习成长、共同进步,做一个职场最贵Tester!

往期推荐

聊聊工作中的自我管理和向上管

经验分享|测试工程师转型测试开发历程

聊聊UI自动化的PageObject设计模式

细读《阿里测试之道》

我在阿里做测开

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 19:27:13  更:2022-06-29 19:29:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 12:39:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码