栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

三、junit接口自动化框架-自定义注解-注解检查

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

三、junit接口自动化框架-自定义注解-注解检查

junit5的自带注解,不能满足需要,所以我们自定义一些注解

自定义注解:

1、自定义注解,@CaseTitle 用例标题 @CaseTag @CaseTags 用例标签,可以打多个,所以有数组 @CheckPoint @CheckPoints 用例检查点,可以是多个。

一、Java自定义注解:

举例一:@CaseDesc

1、新建注解 new Java Class -》Annotation

 

package com.example.autoapi.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD}) // Target表示将来这个注解应用在哪些方面。注解可以应用在类上、方法上(此处只应用在方法上)
@Retention(RetentionPolicy.RUNTIME) //运行时,使用这个这个注解
public @interface CaseDesc {
    String desc();
    String owner();
}

注解编写:

1、运行时,使用这个注解:

@Retention(RetentionPolicy.RUNTIME)

2、该注解作用域,可以作用在类/方法上。此处我们只作用在方法上

@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD})

3、注解的具体内容,我们编写的是@CaseDesc注解,里面包含描述信息 和维护者

String desc();

String owner();

举例二:@CaseTag @CaseTags

@CaseTag,用例的tag,与@CaseDesc的区别是,用例可以写多个@CaseTag 。

@CaseTag

package com.example.autoapi.annotation;

import java.lang.annotation.*;

@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD}) // Target表示将来这个注解应用在哪些方面。注解可以应用在类上、方法上(此处只应用在方法上)
@Retention(RetentionPolicy.RUNTIME) //运行时,使用这个这个注解
@Repeatable(CaseTags.class) // 支持多个CaseTag
public @interface CaseTag {
    String key();
    String value();
}

@CaseTags 

package com.example.autoapi.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD}) // Target表示将来这个注解应用在哪些方面。注解可以应用在类上、方法上(此处只应用在方法上)
@Retention(RetentionPolicy.RUNTIME) //运行时,使用这个这个注解
public @interface CaseTags {
    CaseTag[] value();
}

@CaseTags的内容,是@CaseTag的数组

在@CaseTag上使用@Repeatable(CaseTags.class) ,将两者关联起来。

这样就可以在方法上写多个@CaseTag注解了。

完成以上步骤(以上只是单纯的使用Java的能力写注解),就可以使用这些注解了。可以在case上使用这些注解,但是这些注解没有具体的功能。

想要有具体的功能,我们要将这些自定义注解结合junit5框架。

二、我们要实现哪些功能?

1、注解自身格式的检查(注解是否为空,注解内容是否填写正确)

2、根据注解不同来筛选运行case

3、在case上打报警标签

三、自定义注解与junit5框架相结合--注解自身格式的检查

思路:

1、自定义注解@AutoTest,作为一个载体,来收集使用@AutoTest 注解的测试case上所有的注解

  1. 测试方法/case使用@AutoTest注解
  2. 拿到这个测试方法的名字
  3. 利用反射原理,拿到这个测试方法上的所有注解
  4. 然后对所有注解进行处理

@AutoTest

package com.example.autoapi.annotation;

import com.example.autoapi.extension.CaseAnnotationCheckExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD}) // Target表示将来这个注解应用在哪些方面。注解可以应用在类上、方法上(此处只应用在方法上)
@Retention(RetentionPolicy.RUNTIME) //运行时,使用这个这个注解
@Test
@ExtendWith(CaseAnnotationCheckExtension.class) // 与junit结合,由junit提供。自定义一个扩展类,然后放到这里。走我们的自定义类
public @interface AutoTest {
}

1、要写@Test,这个是junit5运行case用的

2、@ExtendWith(CaseAnnotationCheckExtension.class) 

与junit结合,由junit提供。自定义一个扩展类,然后放到这里。走我们的自定义类。

在这个自定义类里,我们收集所有的注解,然后进行处理

CaseAnnotationCheckExtension

package com.example.autoapi.extension;

import com.example.autoapi.annotation.CaseTitle;
import com.example.autoapi.check.ObserverManager;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

import java.lang.reflect.Method;

// 自定义的扩展类,必须实现框架提供的BeforeTestExecutionCallback接口
// BeforeTestExecutionCallback 在执行case之前,先执行我们的回调
public class CaseAnnotationCheckExtension implements BeforeTestExecutionCallback {
    @Override
    public void beforeTestExecution(ExtensionContext extensionContext) throws Exception {
        Method requiredTestMethod = extensionContext.getRequiredTestMethod(); //拿到使用该注解的方法/测试case
        ObserverManager.of().check(requiredTestMethod); // 利用观察者模式对case上的方法依次进行检查

    }
}

自定义扩展类:CaseAnnotationCheckExtension

要想在junit5框架里,使用这个自定义扩展类,必须实现接口BeforeTestExecutionCallback

BeforeTestExecutionCallback 在执行case之前,先执行我们的回调。

ObserverManager.of().check(requiredTestMethod); // 利用观察者模式对case上的方法依次进行检查

这里我们使用了观察者设计模式,因为要检查很多个注解。

观察者设计模式:

1、我们要写很多个检查方法,比如检查@CaseTitle,注解是否必填,格式是否正确。

检查@CaseTag,注解是否必填,格式是否正确等等,我们要针对每一个注解写一个检查方法。

2、定义观察者接口,里面有检查方法

AnnotationCheckObserver

package com.example.autoapi.check;

import java.lang.reflect.Method;

// 观察者模式
// 每个注解的检查都实现这个接口,便于统一管理/校验注解
public interface AnnotationCheckObserver {
    void check(Method method);
}

3、每个注解的检查都实现这个接口,便于统一管理/校验注解

 CaseTitleCheck 

package com.example.autoapi.check;

import com.example.autoapi.annotation.CaseTitle;
import com.example.autoapi.exception.IllegaFormatException;
import com.example.autoapi.util.RequireUtil;

import java.lang.reflect.Method;

public class CaseTitleCheck implements AnnotationCheckObserver{
    @Override
    public void check(Method method){
        boolean titleSet = method.isAnnotationPresent(CaseTitle.class);
        // 判断注解CaseTitle是否存在
        if(!titleSet){
            throw new IllegaFormatException("title is must");
        }
        CaseTitle caseTitle = method.getAnnotation(CaseTitle.class);
        RequireUtil.requireNotNullOrEmpty(caseTitle.value(),"CaseTitle value is must.eg: @CaseTitle("标题")");
    }
}

里面,写的是对应注解的检查方法

4、ObserverManager。管理所有的检查方法

package com.example.autoapi.check;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ObserverManager {

    private final List observers;

    // 构造器,私有,不能被new
    private ObserverManager(){
        observers = new ArrayList<>();
        observers.add(new CaseTitleCheck());// 添加,检查标题的方法
    }

    // ClassHolder属于静态内部类,在加载类Demo03的时候,只会加载内部类ClassHolder,
    // 但是不会把内部类的属性加载出来
    private static class ClassHolder{
        // 这里执行类加载,是jvm来执行类加载,它一定是单例的,不存在线程安全问题
        // 这里不是调用,是类加载,是成员变量
        private static final ObserverManager holder =new ObserverManager();

    }

    public static ObserverManager of(){//第一次调用getInstance()的时候赋值
        return ClassHolder.holder;
    }

    public void check(Method method){
        // 把case/方法 method ,依次接受各种检查
        for(AnnotationCheckObserver observer:observers){
            observer.check(method);
        }
    }



}

1、每个注解的检查类都实现了AnnotationCheckObserver 这个接口,实现了 check方法

每个类都属于AnnotationCheckObserver接口,所以 创建一个集合,把所有的检查类都放在里面。

然后便利集合里面的元素,依次调用检查check方法。

----------------------------以上就是整个流程--------------------------

接下来完成,其他注解的检查

CaseDescCheck

package com.example.autoapi.check;

import com.example.autoapi.annotation.CaseDesc;
import com.example.autoapi.annotation.CaseTitle;
import com.example.autoapi.exception.IllegaFormatException;
import com.example.autoapi.util.RequireUtil;

import java.lang.reflect.Method;

public class CaseDescCheck implements AnnotationCheckObserver{
    @Override
    public void check(Method method){
        boolean caseDescSet = method.isAnnotationPresent(CaseDesc.class);
        // 判断注解CaseTitle是否存在
        if(!caseDescSet){
            throw new IllegaFormatException("CaseDesc is must");
        }
        CaseDesc caseDesc = method.getAnnotation(CaseDesc.class);
        RequireUtil.requireNotNullOrEmpty(caseDesc.desc(),"CaseDesc desc is must.eg: @CaseDesc(desc="描述",owner="管理者")");
        RequireUtil.requireNotNullOrEmpty(caseDesc.owner(),"CaseDesc owner is must.eg: @CaseDesc(desc="描述",owner="管理者")");

    }
}

CaseTagCheck

package com.example.autoapi.check;

import com.example.autoapi.annotation.CaseDesc;
import com.example.autoapi.annotation.CaseTag;
import com.example.autoapi.exception.IllegaFormatException;
import com.example.autoapi.util.RequireUtil;

import java.lang.reflect.Method;

public class CaseTagCheck implements AnnotationCheckObserver{
    @Override
    public void check(Method method){
        CaseTag[] caseTags = method.getAnnotationsByType(CaseTag.class);
        // 判断是否有CaseTag注解
        // 因为可以写多个,这里获取的是一个数组
        // 数组长度为0时,报异常
        if(caseTags.length==0){
            throw new IllegaFormatException("CaseTag is must");
        }
        for(CaseTag caseTag:caseTags){

            RequireUtil.requireNotNullOrEmpty(caseTag.key(),"CaseTag key is must.eg: @CaseTag(key="key",val="val")");
            RequireUtil.requireNotNullOrEmpty(caseTag.val(),"CaseTag val is must.eg: @CaseTag(key="key",val="val")");

        }

    }
}

CheckPointCheck

package com.example.autoapi.check;

import com.example.autoapi.annotation.CaseTag;
import com.example.autoapi.annotation.CheckPoint;
import com.example.autoapi.exception.IllegaFormatException;
import com.example.autoapi.util.RequireUtil;

import java.lang.reflect.Method;

public class CheckPointCheck implements AnnotationCheckObserver{
    @Override
    public void check(Method method){
        CheckPoint[] checkPoints = method.getAnnotationsByType(CheckPoint.class);
        // 判断是否有CaseTag注解
        // 因为可以写多个,这里获取的是一个数组
        // 数组长度为0时,报异常
        if(checkPoints.length==0){
            throw new IllegaFormatException("CheckPoint is must");
        }
        for(CheckPoint checkPoint:checkPoints){

            RequireUtil.requireNotNullOrEmpty(checkPoint.value(),"CheckPoint is must.eg: @CheckPoint(xxx)");
        }

    }
}

ObserverManager

package com.example.autoapi.check;

import com.google.common.collect.Lists;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ObserverManager {

    private final List observers;

    // 构造器,私有,不能被new
    private ObserverManager(){
        observers = Lists.newArrayList(
                new CaseTitleCheck(),
                new CaseDescCheck(),
                new CaseTagCheck(),
                new CheckPointCheck()
        );
    }

    // ClassHolder属于静态内部类,在加载类Demo03的时候,只会加载内部类ClassHolder,
    // 但是不会把内部类的属性加载出来
    private static class ClassHolder{
        // 这里执行类加载,是jvm来执行类加载,它一定是单例的,不存在线程安全问题
        // 这里不是调用,是类加载,是成员变量
        private static final ObserverManager holder =new ObserverManager();

    }

    public static ObserverManager of(){//第一次调用getInstance()的时候赋值
        return ClassHolder.holder;
    }

    public void check(Method method){
        // 把case/方法 method ,依次接受各种检查
        for(AnnotationCheckObserver observer:observers){
            observer.check(method);
        }
    }



}

------------------------------补充说明---观察者模式----------------------------------

观察者模式

1、创建观察者接口,具体的每个检查类,去实现它,就是为了将来好组建成一个集合,把每个检查类放进去。

2、然后再遍历每个元素的check方法

下一章:

四、junit接口自动化框架-筛选case_傲娇的喵酱的博客-CSDN博客

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/866496.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号