Java之Junit和反射

Posted 我想回家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java之Junit和反射相关的知识,希望对你有一定的参考价值。

Junit,反射

Junit

1.测试的分类:

  • 黑盒测试 : 不需要写代码,给输入值,看程序是否能够输出期望的值。
  • 白盒测试 : 需要进行代码的编写,关注的是程序的具体流程.

2.使用步骤(方法类的命名可以参考阿里巴巴开发手册):

* 步骤:
    1. 定义一个测试类(测试用例)
        * 建议:
            * 测试类名:被测试的类名Test       
            * 包名:xxx.xxx.xx.test        

    2. 定义测试方法:可以独立运行
        * 建议:
            * 方法名:test测试的方法名        testAdd()  
            * 返回值:void
            * 参数列表:空参

    3. 给方法加@Test
    4. 导入junit依赖环境
    
* 判定结果:
    * 红色:失败
    * 绿色:成功
    * 一般我们会使用断言操作来处理结果
        * Assert.assertEquals(期望的结果,运算的结果);

* 补充:
    * @Before:
        * 修饰的方法会在测试方法之前被自动执行
    * @After:
        * 修饰的方法会在测试方法执行之后自动被执行
        
        
// 举个例子
public class Calculator {

    /**
     * 加法运算
     * @param a  加数
     * @param b  被加数
     * @return   和
     */
    public int add(int a,int b){
        return a + b;
    }

    /**
     * 减法运算
     * @param a  减数
     * @param b  被减数
     * @return   差值
     */
    public int sub(int a,int b){
        return a - b;
    }
}

// 测试类的创建
package com.wzlove.test;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @author 王智
 * @date 2018/7/31
 * @描述 测试类
 */

public class CalculatorTest {

    Calculator cal;

    /**
     * 初始化
     */
    @Before
    public void init(){
        // 初始化对象
        cal = new Calculator();
        System.out.println("init==================================================");
    }

    /**
     * 测试加法运算
     */
    @Test
    public void testAdd(){
        // 调用方法
        int result = cal.add(10, 10);
        // 断言
        Assert.assertEquals(20,result);
    }

    /**
     * 测试减法运算
     */
    @Test
    public void testSub(){
        // 调用方法
        int result = cal.sub(10, 10);
        // 断言
        Assert.assertEquals(0,result);
    }

    @After
    public void end(){
        System.out.printf("end========================================");
    }   
}

反射 : 框架的设计灵魂

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
  • 反射:将类的各个组成部分封装为其他对象,这就是反射机制
    • 好处:
      1. 可以在程序运行过程中,操作这些对象。
      2. 可以解耦,提高程序的可扩展性。
  • 获取Class对象的方式:
    1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
      • 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
    2. 类名.class:通过类名的属性class获取
      • 多用于参数的传递
    3. 对象.getClass():getClass()方法在Object类中定义着。
      • 多用于对象的获取字节码的方式
    • 结论:
      同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

    package com.wzlove.reflect;

      /**
       * @author 王智
       * @date 2018/7/31
       * @描述  获取字节码对象的三种方式
       */
      public class GetClassObject {
    
          public static void main(String[] args) throws Exception {
              // 第一种: 使用全类名进行获取
              Class<?> aClass = Class.forName("com.wzlove.reflect.GetClassObject");
              System.out.println(aClass);
              // 第二种: 使用类名的属性获取
              Class aClass1 = GetClassObject.class;
              System.out.println(aClass1);
              // 第三种: 使用类的方法进行获取
              Class<?> aClass2 = new GetClassObject().getClass();
              System.out.println(aClass2);
    
              System.out.println(aClass == aClass1);
              System.out.println(aClass == aClass2);
          }
      }
  • Class对象功能:
    • 获取功能:

      1. 获取成员变量们
        • Field[] getFields() :获取所有public修饰的成员变量
        • Field getField(String name) 获取指定名称的 public修饰的成员变量

        • Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
        • Field getDeclaredField(String name)
      2. 获取构造方法们
        • Constructor<?>[] getConstructors()
        • Constructor

        • Constructor
        • Constructor<?>[] getDeclaredConstructors()
      3. 获取成员方法们:
        • Method[] getMethods()
        • Method getMethod(String name, Class<?>... parameterTypes)

        • Method[] getDeclaredMethods()
        • Method getDeclaredMethod(String name, Class<?>... parameterTypes)

      4. 获取全类名
        • String getName()
  • Field:成员变量
    • 操作:
      1. 设置值
        • void set(Object obj, Object value)
      2. 获取值
        • get(Object obj)
      3. 忽略访问权限修饰符的安全检查
        • setAccessible(true):暴力反射

    // 下面的例子全部使用Student类
    package com.wzlove.reflect;

      /**
       * @author 王智
       * @date 2018/7/31
       * @描述
       */
      public class Student {
    
          private String name;
    
          private int age;
    
          public String sex;
    
          @Override
          public String toString() {
              return "Student{" +
                      "name=‘" + name + ‘‘‘ +
                      ", age=" + age +
                      ", sex=‘" + sex + ‘‘‘ +
                      ‘}‘;
          }
    
          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 String getSex() {
              return sex;
          }
    
          public void setSex(String sex) {
              this.sex = sex;
          }
    
          public Student(String name, int age, String sex) {
              this.name = name;
              this.age = age;
              this.sex = sex;
          }
    
          public Student() {
          }
      }
    
    
      package com.wzlove.reflect;
    
      import java.lang.reflect.Field;
    
      /**
       * @author 王智
       * @date 2018/7/31
       * @描述 利用反射获取对象的成员变量
       */
      public class GetFieldDemo {
    
          public static void main(String[] args) throws Exception {
              // 利用反射获取公有成员变量的步骤
              // 1. 获取反射对象(3种方法)
              Class aClass = Student.class;
              // 2. 获取成员变量
              Field sex =  aClass.getField("sex");
              // 3. 使用Field的方法设置值(需要创建对象)
              Student stu = new Student();
              sex.set(stu,"男");
              // 4. 使用Field的方法获取值
              System.out.println(sex.get(stu));
    
    
    
              // 获取所有成员变量
              // 1. 获取反射对象(3种方法)
              Class aClass1 = Student.class;
              // 2. 获取成员变量
              Field name =  aClass1.getDeclaredField("name");
              // 3. 使用Field的方法设置值(需要创建对象)
              Student stu1 = new Student();
              // 4. 再使用私有变量的时候会报错,所以要跳过检测,也成为暴力反射
              name.setAccessible(true);
              name.set(stu1,"王智");
              // 6. 使用Field的方法获取值
              System.out.println(name.get(stu1));
          }
    
      }
  • Constructor:构造方法
    • 创建对象:
      1. T newInstance(Object... initargs)

      2. 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

    package com.wzlove.reflect;

      import java.lang.reflect.Constructor;
    
      /**
       * @author
       * @date 2018/7/31
       * @描述 利用反射获取对象的构造方法
       */
      public class GetConstructDemo {
    
          public static void main(String[] args) throws Exception {
              // 利用反射获取公有成员变量的步骤
              // 1. 获取反射对象(3种方法)
              Class aClass = Student.class;
              // 2. 使用方法获取构造方法的对象
              Constructor constructor = aClass.getConstructor(String.class, int.class, String.class);
              // 3. 使用Constructor对象初始化对象
              Object obj = constructor.newInstance("张三", 23, "男");
              // 测试输出结果
              System.out.println(obj);
              System.out.println("===================================");
    
              // 无参构造的方法
              // 1. 获取反射对象(3种方法)
              Class aClass1 = Student.class;
              // 2. 使用方法获取构造方法的对象
              Constructor constructor1 = aClass1.getConstructor();
              // 3. 使用Constructor初始化对象
              Object obj1 = constructor1.newInstance();
              // 测试输出结果
              System.out.println(obj1);
    
              // 还有个简化写法,仅仅适用于无参构造,但是我使用JDK10已经不推荐使用了
              Object obj2 = aClass1.newInstance();
              System.out.println(obj2);
    
              // getDeclaredConstructor方法也是获取私有的构造方法,就不演示了
          }
    
      }
  • Method:方法对象
    • 执行方法:
      • Object invoke(Object obj, Object... args)
    • 获取方法名称:
      • String getName:获取方法名

首先在Student中添加两个方法

public void eat(){
    System.out.println("eat..............");
}

public int add(int a, int b){
   return a + b;
}

package com.wzlove.reflect;

import java.lang.reflect.Method;

/**
 * @author 王智
 * @date 2018/7/31
 * @描述 反射执行方法
 */
public class GetMethodDemo {

    public static void main(String[] args) throws Exception {
        // 无参无返回值的方法
        // 1. 创建字节码对象
        Class aClass = Student.class;
        // 2. 创建方法的对象
        Method eat = aClass.getMethod("eat");
        // 3. 执行方法
        Student stu = new Student();
        eat.invoke(stu);

        // 有参有返回值的方法
        // 1. 创建字节码对象
        Class aClass1 = Student.class;
        // 2. 创建方法的对象
        Method add = aClass1.getMethod("add", int.class,int.class);
        // 3. 执行方法
        Student stu1 = new Student();
        Object sum = add.invoke(stu1, 10, 10);
        System.out.println("和为" + sum);
        System.out.println("======================================================");
        // 获取该类所有的方法(这里获取的不仅仅是自己定义的方法,还有从父类继承来的方法)
        Method[] methods = aClass1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            System.out.println(method.getName());
        }
        System.out.println("======================================================");

        // 获取类名
        System.out.println(aClass1.getName());
        // getDeclaredMethod也是同样的道理
    }
}

以上就是反射的简单使用了.举个简单例子,当然这个例子并不完善,将就看

package com.wzlove.reflect;


import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @author 
 * @date 2018/7/31
 * @描述
 * * 案例:
 *  * 需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,
 *  并且执行其中任意方法
 *      * 实现:
 *          1. 配置文件
 *          2. 反射
 *      * 步骤:
 *          1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
 *          2. 在程序中加载读取配置文件
 *          3. 使用反射技术来加载类文件进内存
 *          4. 创建对象
 *          5. 执行方法
 */
public class ReflectDemo {

    public static void main(String[] args) throws Exception {
        // 创建本类的字节码对象
        Class aClass = ReflectDemo.class;
        // 获取类加载器对象
        ClassLoader classLoader = aClass.getClassLoader();
        // 加载配置文件,返回字节流对象
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");

        // 读取配置文件
        // 创建Properties对象
        Properties properties = new Properties();
        properties.load(resourceAsStream);

        // 反射的使用
        Object className = properties.getProperty("className");
        Object methodName = properties.getProperty("methodName");
        // 使用反射创建对象
        Class aClass1 = Class.forName((String) className);
        Constructor constructor = aClass1.getConstructor();
        Object obj = constructor.newInstance();
        // 利用反射获取方法
        Method method = aClass1.getMethod((String) methodName);
        // 使用反射执行方法
        method.invoke(obj);

    }

}








以上是关于Java之Junit和反射的主要内容,如果未能解决你的问题,请参考以下文章

java 反射代码片段

JavaWeb之Java基础知识增强

JavaWeb之Java基础知识增强

JavaWeb之Java基础知识增强

Java基础-单元测试反射注解篇

Junit测试和反射