Unit testing & reflection & annotations

Unit testing

It is to write test code to test the correctness of the smallest functional unit (method).

How did we perform unit testing before? What’s the problem?

Junit unit testing framework

It can be used to test methods. It is open sourced by Junit.

Specific steps

Common annotations of Junit framework

public class StringUtilTest {

    @Test
    @Before
    public void testPrintNumber(){

        StringUtil.printNumber("haha");
        StringUtil.printNumber(null);
    }

    @Test
    public void testGetMaxIndex(){

        int sum = new StringUtil().getMaxIndex("Batman won't hit you");
        System.out.println(sum);

        Assert.assertEquals("warning,warning",6,sum);
    }

    @Test
    @After
    public void testPrint(){

        System.err.println("End");
    }
}

Reflection

Reflection is: loading a class and allowing programmatic dissection of various components in the class (member variables, methods, constructors, etc.).

What does reflection teach?

Three ways to obtain Class objects

1. Directly use class name.class to obtain: Class c1 = class name.class

2. Call the method provided by Class: Class c2 = Class.forName(“Full class name”)

3. Call the method provided by Object: Class c3 = object.getClass()

public class Demo1 {

    @Test
   public void testDemo01() throws ClassNotFoundException {
       Class catClass = Cat.class;
       System.out.println(catClass.getName());

       Class aClass = Class.forName("com.itheima.b_reflection.Cat");
       System.out.println(aClass);

       Class aClass1 = new Cat().getClass();
       System.out.println(aClass1);
   }
}

Get the constructor of the class

/*
Get the constructor [the following is the method of Class]
    Constructor<?>[] getConstructors() gets all public constructors (only public modified ones can be obtained)
    Constructor<?>[] getDeclaredConstructors() Get all constructors (you can get them as long as they exist)
    Constructor<T> getConstructor(Class<?>... parameterTypes) Gets a public constructor (only public-modified ones can be obtained)
    Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) Get a certain constructor (you can get it as long as it exists)

Use a constructor (create an object) [The following is the method of Constructor]
    T newInstance(Object... initArgs) calls the constructor represented by this constructor object, passes in the parameters, completes the initialization of the object and returns
    public void setAccessible(boolean flag) is set to true, which means that checking access control (violent reflection) is prohibited

Notice
    If you want to use private modified constructor reflection to create an object, violent reflection is required (prohibiting the JVM from checking the access permissions of the constructor)
*/
public class Demo2 {

    @Test
    public void testConstructor() throws NoSuchMethodException {

        Class<Cat> clazz = Cat.class;

        //Get all constructors (public)
        Constructor[] constructors = clazz.getConstructors();

        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

        System.out.println("====================================");

        Constructor<Cat> constructor = clazz.getConstructor();
        System.out.println(constructor);
        System.out.println("===============================");
        Constructor<Cat> declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
        System.out.println("Method name:" + declaredConstructor.getName() + "Number of parameters:" + declaredConstructor.getParameterCount());
    }

    @Test
    public void testNew() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        Class calazz = Cat.class;

        Constructor declaredConstructor = calazz.getDeclaredConstructor(String.class, int.class);

        declaredConstructor.setAccessible(true);

        Cat Garfield = (Cat)declaredConstructor.newInstance("Garfield", 3);

        System.out.println(Garfield);
    }
}

Get the member variables of the class

public class Demo3 {

   @Test
    public void testField() throws NoSuchFieldException {

       Class<Cat> catClass = Cat.class;

       //Get all public member variables of the class (only public modified ones can be obtained)
       Field[] fields = catClass.getFields();
       for (Field field : fields) {
           System.out.println(field);
       }

       System.out.println("===============");
       //Get all member variables of the class
       Field[] declaredFields = catClass.getDeclaredFields();
       for (Field declaredField : declaredFields) {
           System.out.println(declaredField.getName() + declaredField.getType());
       }
       System.out.println("====================");
       Field a = catClass.getField("a");//Get the member variables of a certain class, you can get them as long as they exist
       System.out.println(a);

       Field age = catClass.getDeclaredField("age");
       System.out.println(age);
   }

   @Test
   public void test2() throws NoSuchFieldException, IllegalAccessException {

       Classclazz = Cat.class;

       Cat cat = new Cat();
      // System.out.println(cat);

       Field age = clazz.getDeclaredField("age");

       Field name = clazz.getDeclaredField("name");
       //violent reflection
       age.setAccessible(true);
       name.setAccessible(true);

       age.set(cat,5);
       name.set(cat,"haha");
       System.out.println(cat);

       //Get value
       Object o = age.get(cat);
       System.out.println(o);
   }
}

Get the member methods of the class

/*
Get member method [provided by Class]
    Method[] getMethods() gets all the public member methods of the class (only public modified ones can be obtained)
    Method[] getDeclaredMethods() Gets all member methods of the class (you can get them as long as they exist)
    Method getMethod(String name, Class<?>... parameterTypes) Gets a public member method of the class (only public modified ones can be obtained)
    Method getDeclaredMethod(String name, Class<?>... parameterTypes) Gets a certain member method of the class (you can get it as long as it exists)

Use member methods (execution methods) [provided by Method]
    public Object invoke(Object obj, Object... args) triggers the execution of this method on an object.
    public void setAccessible(boolean flag) is set to true, which means that checking access control (violent reflection) is prohibited

Notice
    If you want to use private modified member methods, you need violent reflection
*/
public class Demo4 {

    @Test
    public void testMethods() throws NoSuchMethodException {
        Class<Cat> catClass = Cat.class;

        Method[] methods = catClass.getMethods();
        for (Method method : methods) {
            System.out.println("Method name:" + method.getName() + "Return value type:" + method.getReturnType());
        }

        System.out.println("============================");

        Method[] declaredMethods = catClass.getDeclaredMethods();

        for (Method declaredMethod : declaredMethods) {
            System.out.println("Method name:" + declaredMethod.getName() + "Return value type" + declaredMethod.getReturnType());
        }

        System.out.println("============================");
        Method eat = catClass.getDeclaredMethod("eat");
        System.out.println("Method name:" + eat.getName() + "Return value type" + eat.getReturnType());

        System.out.println("============================");
        Method eat1 = catClass.getDeclaredMethod("eat", String.class);
        System.out.println("Method name:" + eat1.getName() + "Return value type" + eat1.getReturnType());
    }

    @Test
    public void tese2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        Class<Cat> clazz = Cat.class;

        Method eat = clazz.getDeclaredMethod("eat", String.class);

        eat.setAccessible(true);

        Cat cat = new Cat();
        Object invoke = eat.invoke(cat, "");
        System.out.println(invoke);
    }
}

Case:

/*
reflection case
    For any object, the framework can print the field name and corresponding value of the object on the console.

*/
public class Demo5 {
    public static void main(String[] args) {
        //1. Prepare two objects
        Student student = new Student("Liu Yan", 40, 'Female', 167.5, "Actress");
        Teacher teacher = new Teacher("BoNiu", 6000);

        //2. Call method

        print(student);
    }

    public static void print(Object o) {

        try {
            Class clazz = o.getClass();

            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {

                declaredField.setAccessible(true);

                String name = declaredField.getName();
                Object o1 = declaredField.get(o);
                System.out.println(name + o1);
            }
        }catch (Exception e){
        }

    }
}



class Student{
    public Student(String name, int age, char sex, double height, String hobby) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.hobby = hobby;
    }

    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;
}

class Teacher {
    public Teacher(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    private String name;
    private double salary;
}

The role of reflection

Annotations

Meta-annotation

Refers to: annotations that modify annotations.

Annotation parser

It is to determine whether there are annotations on the class, method, and member variables, and parse the content in the annotations.

How to parse annotations

public class ClassNameCheckParser {

    public static void checkClassName(){
        //1. Store classes that do not comply with specifications
        ArrayList<String> list = new ArrayList<>();

        //2. Get all classes under the specified package
        Set<Class> clazzSet = ClassUtil.getClasses("com.itheima.c_annotation.example");
        //3. Traverse the set collection to find the class annotated with @ClassNameCheck'

        for (Class clazz : clazzSet) {

            //Determine whether there is an annotation on a certain class
            if(clazz.isAnnotationPresent(ClassNameCheck.class)){

                //Get the class name
                String simpleName = clazz.getSimpleName();
                //Check if the class name starts with Heima
                if(!simpleName.startsWith("Hei")){

                    list.add(simpleName);
                }
            }
        }

        //Determine whether there are any in the collection that do not meet the specifications, and if so, save them directly
        if(list.size() > 0) {

            System.out.println("The following class name does not comply with the specification");
            for (String name : list) {
                System.out.println(name);
            }
            throw new RuntimeException("Program terminated");
        }

    }

}