首页 > 其他分享 >05.单元测试、注解和反射

05.单元测试、注解和反射

时间:2023-04-16 16:35:36浏览次数:33  
标签:String 05 单元测试 class 注解 方法 public name

1、单元测试

  1. 什么是单元测试?单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性。

  2. 目前测试方法是怎么进行的,存在什么问题?

    • 只有一个main方法,如果一个方法的测试失败了,其他方法测试会受到影响

    • 无法得到测试的结果报告,需要程序员自己去观察测试是否成功。

    • 无法实现自动化测试。

  3. Junit单元测试框架,JUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当学习并使用JUnit编写单元测试。此外,几乎所有的IDE工具都集成了IUnit,这样我们就可以直接在IDE中编写并运行IUnit测试,JUnit目前最新版本是5。

  4. JUnit优点

    • JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。

    • Junit可以生成全部方法的测试报告。

    • 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。

  5. Junit快速入门

    • 需求:使用单元测试进行业务方法预期结果、正确性测试的快速入门

    • 分析:

      • 将Unit的iar包导入到项目中,IDEA通常整合好了Junit框架,一般不需要导入。如果IDEA没有整合好,需要自己手工导入如下2个IUnit的iar包到模块

      • 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。

      • 在测试方法上使用@Test注解,标注该方法是一个测试方法

      • 在测试方法中完成被测试方法的预期正确性测试。选中测试方法,选择“JUnit运行”,如果测试良好则是绿色;如果测试失败,则是红色

    • 使用示例:

      //有待测试方法的类
      public class TestDemo {
          //返回 1 + 2.....+100的值。
          public int sum(){
              int result = 0;
              for (int i = 0; i < 100; i++) {
                  result += i;
              }
              return result;
          }
      
          //一个会出问题的方法。
          public void div(){
              System.out.println(5/0);
          }
      }
      //测试
      public class Test {
      
          @org.junit.Test
          public void  testSum(){
              TestDemo demo = new TestDemo();
              int sum = demo.sum();
              //通常会使用Assert.assertEquals()方法来测试有返回值的方法。
              //第一个参数表示返回值有误的提示信息。
              //第二个参数表示期待的返回值
              //第三个表示实际上返回的值。
              Assert.assertEquals("返回值有误",5050,sum);
          }
      
          @org.junit.Test
          public void testDiv(){
              TestDemo demo = new TestDemo();
              demo.div();
          }
      }
      
  6. Junit常用方法

    • @Test:测试方法

    • @Before:用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次。

    • @After:用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次。

    • @BeforeClass:用来静态修饰方法,该方法会在所有测试方法之前只执行一次。

    • @AfterClass:用来静态修饰方法,该方法会在所有测试方法之后只执行一次。

    • 开始执行的方法,用于初始化资源。执行完之后的方法,用于释放资源。

2、反射

  1. 反射概述

    • 反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这这个类全部成分。

    • 反在运行时,可以直接得到这个类的构造器对象:Constructor

    • 反在运行时,可以直接得到这个类的成员变量对象:Field

    • 反在运行时,可以直接得到这个类的成员方法对象:Method

    • 反这种运行时动态获取类信息以及动态调用类中成分的能力称为java语言的反射机制。

  2. 反射的关键:反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。

  3. 获取反射类对象

    • 获取反射类对象一般有三种方式

    • 使用示例:三个打印结果都为class shh.People,也就是说一个类只有一个class对象。

      public static void main(String[] args) throws Exception {
      
          //方式一:Class.forName(全类名),参数为包名.包名....类名,完整的类名
          Class<?> class01 = Class.forName("shh.People");
          System.out.println(class01);
      
          //方式二:类名.class
          Class<People> class02 = People.class;
          System.out.println(class02);
      
          //方式三:对象.getClass(),getClass()方法为老祖宗Object对象的方法。
          People people = new People();
          Class<? extends People> class03 = people.getClass();
          System.out.println(class03);
      }
      
  4. 反射获取构造器对象

    • 使用反射可以获取构造器对象

    • Class类中用于获取构造器的方法

      • Constructor<?>[] getConstructors():返回所有构造器对象的数组(只能拿public的)

      • Constructor<?>[] getDeclaredConstructors():返回所有构造器对象的数组,存在就能拿到

      • Constructor getConstructor(Class<?>... parameterTypes):返回单个构造器对象(只能拿public的)

      • Constructor getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造器对象,存在就能拿到

    • 示例

      public static void main(String[] args) throws Exception{
      
          //获取People类的class对象。
          Class<People> peopleClass = People.class;
      
          //getConstructors(),获取所有的构造器对象,private方法无法获取。
          Constructor<?>[] constructors = peopleClass.getConstructors();
          
          //getDeclaredConstructors(),获取所有的构造器对象,私有方法也可以获取到。
          Constructor<?>[] declaredConstructors = peopleClass.getDeclaredConstructors();
          
          //getConstructor(类型.class),获取指定参数类型的一个构造器。私有方法无法获取
          Constructor<People> constructor = peopleClass.getConstructor(String.class);
          
          //getDeclaredConstructor(类型.class),获取指定参数类型的一个构造器,私有方法也可以获取到,
          Constructor<People> declaredConstructor = peopleClass.getDeclaredConstructor(String.class);
      
      }
      
  5. 使用构造器对象创建类对象

    • Constructor类中用于创建对象的方法

      • T newlnstance(Object... initargs):根据指定的构造器创建对象

      • public void setAccessible(boolean flag):设置为true表示取消访问检查,进行暴力反射,也就是说私有构造器对象也可以创建对象。

    • 示例

      public class People {
      
          private String name;
          private int age;
          //私有构造器
          private People(){}    
          public People(String name) {
              this.name = name;
          }
          public People(String name, int age) {
              this.name = name;
              this.age = age;
          }
      }
      
      //测试
      public static void main(String[] args) throws Exception{
      
          //获取People类的class对象。
          Class<People> peopleClass = People.class;
      
          //获取空参数的私有构造器
          Constructor<People> privateConstructor = peopleClass.getDeclaredConstructor();
          //People people = privateConstructor.newInstance(); 执行失败,私有构造器不能创建对象。
          privateConstructor.setAccessible(true);  //暴力反射,让私有构造器也可以创建对象
          People people = privateConstructor.newInstance(); //执行成功
      
          //获取两个参数的构造器
          Constructor<People> constructor = peopleClass.getConstructor(String.class, Integer.class);
          People people1 = constructor.newInstance("小明", 10);
      
      }
      
  6. 反射获取成员变量对象

    • 使用反射可以获取成员变量对象

    • 获取成员变量对象的方法

      • Field getField(String name):根据成员变量名获得对应Field对象,只能获得public修饰的成员变量

      • FField getDeclaredField(String name):根据成员变量名获得对应Field对象,只要申明了就可以得到(可以获取任何访问权限的成员变量)

      • Field[] getFields():获得所有的成员变量对应的Field对象,只能获得public的成员变量

      • Field[] getDeclaredFields():获得所有的成员变量对应的Field对象,只要申明了就可以得到

    • Field类中操作成员变量的方法,给成员变量赋值和取值

      • void set(Object obj, object value):给对象注入某个成员变量数据

      • Object get(Object obj):获取对象的成员变量的值。

      • void setAccessible(true):暴力反射,设置为可以直接访问私有类型的属性。

      • Class getType0):获取属性的类型,返回Class对象。

      • String getName():获取属性的名称。

    • 使用示例

      public class People {
      
          private String name;
          public int age;
      
          public People(String name, Integer age) {
              this.name = name;
              this.age = age;
          }
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
          public int getAge() {
              return age;
          }
          public void setAge(int age) {
              this.age = age;
          }
      }
      //测试
      public static void main(String[] args) throws Exception{
      
          //获取People类的class对象。
          Class<People> peopleClass = People.class;
      
          //Field name = peopleClass.getField("name");//执行失败,getField不能获取私有成员变量
          //使用getField()获取public修饰的成员变量。
          Field age = peopleClass.getField("age");
          //使用getDeclaredField()获取私有成员变量。
          Field name = peopleClass.getDeclaredField("name");
      
          //使用set()方法修改变量内容。
          People people = new People("小明",10);
          //name.set(people,"小红"); 执行失败,私有的成员变量不允许修改变量内容
          name.setAccessible(true);
          name.set(people,"小红");  //先使用setAccessible暴力反射,就可以修改变量内容了。
      
          //获取某个对象的变量信息
          Class<?> type = age.getType(); //获取变量类型
          String name1 = age.getName(); //获取变量名
      }
      
  7. 反射获取成员方法对象

    • 使用反射可以获取成员方法对象

    • 获取成员方法对象的方法

      • Method[] getMethods():返回所有成员方法对象的数组(只能拿public的)

      • Method[] getDeclaredMethods():返回所有成员方法对象的数组,存在就能拿到

      • Method getMethod(String name,Class<?>... parameterTypes):返回单个成员方法对象(只能拿public的)

      • Method getDeclaredMethod(String name,Class<?>... parameterTypes):返回单个成员方法对象,存在就能拿到

    • 执行方法的方法:Object invoke(Object obj,Object... args)

      • 参数一:用obj对象调用该方法,指定要调用方法的对象

      • 参数二:调用方法的传递的参数(如果没有就不写)

      • 返回值:方法的返回值(如果没有就不写)

    • 使用示例

      public class People {
      
          private String name;
          public People(String name) {
              this.name = name;
          }
      
          //一个公共的方法,会吃饭,无返回值
          public void eat(String thing){
              System.out.println(this.name + "会吃"+thing);
          }
          //一个私有的方法,返回名字
          private String getName(){
              return this.name;
          }
      }
      //测试
      public static void main(String[] args) throws Exception {
          Class<People> p = People.class;
      
          //获取公共方法
          Method eat = p.getMethod("eat",String.class);
          //getDeclaredMethod可以 获取私有方法。
          //Method getName = p.getMethod("getName"); 执行失败,不能获取私有方法
          Method getName = p.getDeclaredMethod("getName");
      
          //invoke方法,用于执行某个对象的方法。
          People people = new People("小明");
          eat.invoke(people,"冰淇淋");
          //String invoke = (String)getName.invoke(people); 执行失败,私有方法不可被执行
          getName.setAccessible(true);
          //暴力反射之后,私有方法就可以被执行了
          String invoke = (String)getName.invoke(people);
          System.out.println(invoke);
      }
      
  8. 反射的应用

    • 反射的作用-绕过编译阶段为集合添加数据

      • 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。

      • 泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。所以就可以使用反射,来为集合添加数据

      • 演示

        public static void main(String[] args) throws Exception {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            //list.add("你好");   编译报错
            Class<? extends ArrayList> c = list.getClass(); //获取class对象
            Method add = c.getMethod("add", Object.class); //获取add方法对象
            add.invoke(list,"你好");   //执行成功
            System.out.println(list);  //输出:[1, 2, 你好]
        }
        
      • 实际上有另一种方式可以突破泛型的约束

        public static void main(String[] args) throws Exception {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            //list.add("你好");   编译报错
            ArrayList list2 = list;  //将list2指向list对象。
            list2.add("你好");     //此时list2对象是没有被泛型约束的
            System.out.println(list);  //输出:[1, 2, 你好]
        }
        
    • 反射的作用- 反射做通用框架

      • 需求:给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文
        件中去。

      • 分析

      • 代码实现:

        //使用反射获取对象信息并打印到文件上
        public static void getMeg(Object obj){
            PrintStream ps = null;
            try {
                //使用打印流,指定要打印到哪个文件中去。
                ps = new PrintStream(new FileOutputStream("C:\\Users\\86158\\Desktop\\test.txt",trued));
                Class<?> c = obj.getClass();
                String className = c.getName(); //获取类名
                ps.println("================="+className+"==============");
                Field[] fields = c.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    Object value = field.get(obj);
                    ps.println(fieldName + "="+value);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                if(ps != null){
                    ps.close();
                }
            }
        }
        
        // 测试  
        public static void main(String[] args) throws Exception {
            getMeg(new Teacher("小红",465));
            getMeg(new Student("小明",45,'男',180,"王者荣耀"));
        }
        

        结果:

3、注解

  1. 注解概述

    • Java注解(Annotation)又称Java标注,是JDK50引入的一种注释机制。Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。

    • 注解的作用:对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。

  2. 自定义注解

    • 定义注解的基本形式:default 默认值 可以省略。

    • 注意:

      • value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!!但是如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的。

      • default 默认值 可以省略。设置默认值之后的属性,在使用注解时,可以不为其赋值,直接使用默认值即可。若不设置默认值,则必须为其赋值,除了特殊属性value之外,赋值语句必须为“属性名=属性值”

    • 自定义注解示例:

      //自定义的注解
      public @interface MyAnnotation {
          public String value();
          //public 修饰符可以省略,因为默认就是public修饰
          String name() default "shh";
          //设置默认值之后,在使用注解时,可以省略该属性值的赋值过程
          public int age() default 18;
      }
      
      //使用自定义注解
      public class Main {
      
          //由于MyAnnotation注解中,除了value属性之外,其他的属性都有默认值
          //所以此处可以省略 “value=” 以及 其他属性值赋值的语句。
          @MyAnnotation("shh")
          public void aMethod01(){}
      
          //必须为所有属性值赋值,除非它有默认值。赋值语句必须为 “属性名=值”。
          @MyAnnotation(value = "shh",name = "sfaf",age = 16)
          public void aMethod02(){}
      }
      
  3. 元注解

    • 概述:元注解就是注解注解的注解,也就是对注解使用的注解。

    • 元注解有两个:

      • @Target:约束自定义注解只能在哪些地方使用

      • @Retention:申明注解的生命周期

    • @Target中可使用的值定义在 ElementType枚举类中,常用值如下

      • TYPE,类,接口

      • FIELD 成员变量

      • METHOD 成员方法

      • PARAMETER 方法参数

      • CONSTRUCTOR 构造器

      • LOCAL VARIABLE 局部变量

    • @Retention中可使用的值定义在 RetentionPolicy 枚举类中,常用值如下

      • SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在

      • CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值。

      • RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

    • target使用示例

      //定义了一个注解,使用target元注解标注它只能被用于方法和成员变量中。
      @Target({ElementType.FIELD,ElementType.METHOD})
      public @interface MyAnnotation {
          public String value();
      }
      
      //测试
      @Target({ElementType.FIELD,ElementType.METHOD})
      //@MyAnnotation("shh") 报错,该注解不能注解类。
      public class Main {
          //注解成员变量、方法都没有异常。
          @MyAnnotation("shh")
          private String name;
          @MyAnnotation("shh")
          public void aMethod02(){}
      }
      
  4. 注解解析 (

    标签:String,05,单元测试,class,注解,方法,public,name
    From: https://www.cnblogs.com/Chihuatanio/p/17314150.html

相关文章

  • @Valid注解
    使用@Valid注解如:publicRespBeandoLogin(@ValidLoginVologinVo,HttpServletRequestrequest,HttpServletResponseresponse){log.info("{}",loginVo);returntUserService.doLongin(loginVo,request,response);}LoginVo@Datapubl......
  • @RestControllerAdvice注解 @ExceptionHandler注解
    RestControllerAdvice+ExceptionHandler这两个注解的组合,被用作项目的全局异常处理。一旦项目中发生了异常,就会进入使用了RestControllerAdvice注解类中使用了ExceptionHandler注解的方法。下面是一些项目全局异常的处理@ControllerAdvice(annotations={RestController.class,......
  • 2005-text1
    2005-text1vanish消失,突然不见v.reputation名声slack松懈,懈怠,偷懒outrage使震怒;愤怒v.n.outraged气愤的assumption假定co-operative合作的,协作的co-operation合作counterpart与对方地位相当的人characteristic特征,特性;特有的c......
  • Q:数据库方法的传播特性,外层方法的事务注解@Transactional默认会影响本方法么
    外层方法的事务注解默认会影响本方法么涉及知识:事务的传播特性实验前推测:目前了解内、外方法某个发生异常执行回滚是否影响另一个方法是由配置的哪个传播特性决定的。推测内方法出现异常要导致外方法的事务也要回滚,因为这个在现实场景最普遍。实验:描述:roleService.inse......
  • Lenovo Legion 5 15IMH05H电脑 Hackintosh 黑苹果efi引导文件
    原文来源于黑果魏叔官网,转载需注明出处。(下载请直接百度黑果魏叔)硬件型号驱动情况主板LenovoLegion515IMH05H处理器Intel(R)Core(TM)[email protected]已驱动内存16GB2933MHzDDR4已驱动硬盘Intel760p512GB已驱动显卡Intel(R)UHDGraphics630(1GB)......
  • 人月神话阅读笔记05
    继续阅读《人月神话》削足适履我们都很清楚的是,在大型项目中,所有任务大致会被分成几个小组来进行分工合作,在分工合作的过程中,各个小组都有着自己的频率和效率;若是缺乏一定的沟通的话,很容易产生在整体项目中进度的不一致、用户需求的分歧等众多矛盾;所以,在小组分工的项目里面,不......
  • SpringBoot常用注解
    本文整理了SpringBoot常用注解,主要讲解这些注解的用法,并附上一致思维导图。SpringBoot常用注解组件相关注解@Controller用于修饰MVC中controller层的组件,SpringBoot中的组件扫描功能会识别到该注解,并为修饰的类实例化对象,通常与@RequestMapping联用,当SpringMVC获取到请求时......
  • Spring很常用的@Conditional注解的使用场景和源码解析
    你好,我是刘牌!介绍今天要分享的是Spring的注解@Conditional,@Conditional是一个条件注解,它的作用是判断Bean是否满足条件,如果满足条件,则将Bean注册进IOC中,如果不满足条件,则不进行注册,这个注解在SpringBoot中衍生出很多注解,比如@ConditionalOnProperty,@ConditionalOnBean,@Conditi......
  • Chapter5 注解
    注解importmatplotlib.pyplotaspltimportnumpyasnpx=np.linspace(-3,3,50)y=2*x+1plt.figure(num=1,figsize=(8,5),)plt.plot(x,y,)ax=plt.gca()ax.spines['right'].set_color('none')ax.spines['top'].set_color('......
  • POJ 1905 Expanding Rods (二分+计算几何+精度处理)
    题目地址:POJ1905用二分枚举h,然后判断弧长是否符合条件。重点还是在精度问题上,具体看代码吧。。#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#include<stdlib.h>#include<map>#include<set>#include......