单元测试
概述:
-
Junit
JUnit 是一个 Java 编程语言的单元测试工具。是一个非常重要的测试工具
Junit特点
JUnit 是一个开放源代码的测试工具
- JUnit 可以很方便的对Java中的方法进行测试,提高测试效率
JUnit 在一个条中显示进度。如果运行良好则是绿色;如果运行失败,则变成红色
Junit常用注解
@Test 表示测试该方法
@Before 每次在测试方法运行前,都会运行
@After 每次在测试方法运行后,都会运行
@BeforeClass 修饰静态方法,在所有测试的方法运行前运行,只会运行一次
@AfterClass 修饰静态方法,在所有测试的方法运行后运行,只会运行一次 :::反射
反射机制
在程序的运行过程中, 通过Class对象得到类中的信息(构造方法,成员方法,成员变量), 并操作他们这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
-
三种获取Class对象的方式
类名.class
- 对象.getClass()
-
Class类中的方法
String getSimpleName(): 获得类名
- String getName(): 获得类全名:包名+类名
反射获取构造方法Constructor并使用
Class类中获取构造方法
- Constructor<?>[ ] getConstructors():返回public修饰的所有构造方法对象的数组
- Constructor
getConstructor(Class<?>… parameterTypes):返回public修饰的单个构造方法对象 - Constructor<?>[ ] getDeclaredConstructors():返回任意权限的所有构造方法对象的数组
Constructor
getDeclaredConstructor(Class<?>… parameterTypes):返回任意权限的单个构造方法对象 Constructor类中用于创建对象的方法
T newInstance(Object… initargs):根据指定的构造方法创建对象
- setAccessible(boolean flag):设置为true,表示允许对私有权限的访问
反射获取成员方法Method并使用
Class类中获取成员方法
- Method[] getMethods():返回所有public的成员方法对象的数组,包括继承的
- Method getMethod(String name, Class<?>… parameterTypes) :返回单个public的成员方法对象
- 参数name:表示方法名 ;参数parameterTypes:表示方法的形参类型
- Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getDeclaredMethod(String name, Class<?>… parameterTypes):返回单个成员方法对象
Method类中的方法
Object invoke(Object obj, Object… args):运行方法
- 参数obj:调用成员方法的对象(如果调用的是静态方法,该参数为null即可)
- 参数args :可变参数,表示调用方法时传递的实参(如果没有就不写)
- 返回值Object :方法的返回值(如果没有就不用接)
反射获取成员变量Field并使用
Class类中获取成员变量
- Field getField(String name):返回单个公共成员变量对象
- Field[] getFields():返回所有公共成员变量对象的数组,包括继承的public成员变量
- Field getDeclaredField(String name):返回单个成员变量对象
Field[] getDeclaredFields():返回所有本类成员变量对象的数组 不包括继承的
Field类中的方法
void set(Object obj, Object value):赋值。参数obj为成员变量所在的对象,参数value为成员变量的值
- Object get(Object obj) :获取值。参数obj为成员变量所在的对象 :::
注解(Annotation)
概述
- public @interface 注解名称 {
- public 属性类型 属性名();
- }
注解中的属性可以有默认值,格式为:数据类型 属性名() default 默认值;
属性类型可以为基本数据类型,String,Class,注解,枚举及以上类型的数组
自定义注解的使用
元注解
元注解是指: 修饰注解的注解
@Target 指定注解能在哪里使用
@Retention 注解的生命周期,可以理解为保留时间
@Documented 表示注解在生成帮助文档时会保留下来
@Inherited 表示该注解会被子类继承
@Target
- 作用:用来标识注解使用的位置
可使用的值定义在 ElementType枚举类 中,常用值如下:
作用:用来标识注解的生命周期
可使用的值定义在 RetentionPolicy枚举类 中,常用值如下:
使用Java反射技术,获得注解的属性数据的过程,称为注解解析
注解解析相关方法:
T getAnnotation(Class
annotationClass) 根据注解类型获得对应注解对象 - Annotation[] getAnnotations() 获得当前结构上使用的所有注解
- boolean isAnnotationPresent(Class
annotationClass) 判断当前结构上是否使用了指定的注解,如果使用了则返回true,否则false Field,Method,Constructor,Class 等反射相关的类可以调用以上方法
::: ```java import org.junit.Test;
public class Demo {
@Test
public void a() {
System.out.println("测试块1");
}
@Test
public void b() {
System.out.println("测试块2");
}
@Test
public void c() {
System.out.println("测试块3");
}
}
```java
public class Person {
//成员变量
private String name;
private int age;
//-------构造方法-------
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name){
this.name = name;
}
protected Person(int age){
this.age = age;
}
//-----------------------
//-------get和set方法-------
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;
}
//-------其他成员方法-------
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private int work(int hour){
System.out.println("一天工作"+hour+"小时");
return hour*100; //工资
}
public static void run(){
System.out.println("静态的run方法");
}
public int show(int a, int b) {
return a + b;
}
}
/*
三种获取Class对象的方式
方式1:类名.class
方式2:对象名.getClass()
方式3:Class.forName("类全名"); //类全名就是 包名.类名
Class类中的方法:
String getSimpleName(); 获得类名
String getName(); 获得类全名:包名.类名
注意:
这三种方式获取的是同一个Class对象
一个类只有一个Class对象(可以理解为一个类只有一个字节码文件)
*/
public class Demo00Reflect {
public static void main(String[] args) throws ClassNotFoundException {
//方式1:类名.class
Class<Person> clazz1 = Person.class;
System.out.println(clazz1);
//方式2:对象名.class
Person p = new Person();
Class<? extends Person> clazz2 = p.getClass();
System.out.println(clazz2);
//方式3:Class.forname("类全名")
Class<?> clazz3 = Class.forName("demo.test.Person");
System.out.println(clazz3);
//三种方式获取的是同一个Class对象
System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);
//获得类全名,包名.类名
System.out.println(clazz1.getName());
//获得类名
System.out.println(clazz1.getSimpleName());
}
}
public class Demo01Reflect {
public static void main(String[] args) throws Exception {
//获取Class对象
Class<Person> clazz = Person.class;
//反射获取person类所有公开的构造方法
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
//获取person类中公开的无参构造方法
Constructor<Person> con1 = clazz.getConstructor();
System.out.println(con1);
//获取person类公开的带参构造方法
Constructor<Person> con2 = clazz.getConstructor(String.class, int.class);
System.out.println(con2);
}
}
/*
反射方式获取带参构造方法,并创建对象
反射方式获取无参构造方法,并创建对象
反射方式获取私有构造方法,并创建对象
Constructor类代表 "构造方法" 这类事物,
而一个Constructor对象就代表一个具体的构造方法,可以用于创建该构造方法对应的对象。
Constructor类中创建对象的方法:
T newInstance(Object... initargs):根据指定的构造方法创建对象,
setAccessible(boolean flag):设置为true,表示取消访问检查
反射方式创建对象特点:
代码更复杂,但是灵活度更高,而且可以使用任何权限的构造方法创建对象
*/
public class Demo02Reflect {
public static void main(String[] args) throws Exception {
//获取Class对象
Class<Person> clazz = Person.class;
//nweInstance(构造方法的实参),使用构造器创建对象
Constructor<Person> con = clazz.getConstructor(String.class, int.class);
//创建对象
Person p1 = con.newInstance("张三", 23);
System.out.println(p1);
//反射调用私有构造器
Constructor<Person> dCon = clazz.getDeclaredConstructor(String.class);
//暴力反射,设置允许访问私有构造器
dCon.setAccessible(true);
//创建对象
Person p = dCon.newInstance("李四");
System.out.println(p);
}
}
/*
Method类:
表示 "成员方法" 这类事物,每一个Method对象代表一个成员方法。
Class类中获取成员方法:(Method对象)
1.获取public的成员方法:
Method[] getMethods():获取所有成员方法,包括从父类继承的。
Method getMethod(String name, Class<?>... parameterTypes) :获取单个成员方法。
参数name:表示方法名
参数parameterTypes:表示方法的形参类型
2.获取本类中任何权限的成员方法:
Method[] getDeclaredMethods():获取所有成员方法,不包括继承的。
Method getDeclaredMethod(String name, Class<?>... parameterTypes):获取单个成员方法对象。
注意: int.class 和 Integer.class 是不一样的
*/
public class Demo03Reflect {
public static void main(String[] args) throws Exception{
//类全名获取字节码
Class<?> clazz = Class.forName("demo.test.Person");
//获取所有的public的方法,包括继承下来的方法
Method[] met1 = clazz.getMethods();
for (Method m1 : met1) {
System.out.println(m1);
}
System.out.println();
//获取任意权限的所有方法,只能获取本类的所有方法
Method[] met2 = clazz.getDeclaredMethods();
for (Method m2 : met2) {
System.out.println(m2);
}
}
}
/*
需求: 利用反射根据文件中的不同类名和方法名,创建不同的对象并调用方法。
分析:
1.通过Properties加载配置文件 load(字符流)
2.从Properties中获取类名和方法名
3.通过类名反射得到Class对象
4.通过Class对象创建一个对象
5.通过Class对象得到方法
6.调用方法
*/
public class Demo05Reflect {
public static void main(String[] args) throws Exception {
//通过properties加载配置文件
Properties p = new Properties();
p.load(new FileReader("Day13Reflect\\ceshi\\config.properties"));
//从properties中获取类名和方法名
String className = p.getProperty("className");
String methodName = p.getProperty("methodName");
//使用反射运行方法
//获取字节码对象forName
Class<?> clazz1 = Class.forName(className);
//通过Class对象创建方法
Method met1 = clazz1.getMethod(methodName);
//通过Class对象创建对象
Object obj = clazz1.getConstructor().newInstance();
//运行方法
met1.invoke(obj);
}
}
/*
Day13Reflect\\ceshi\\config.properties
className=demo.test.Student
methodName=study
*/
@Anno
@Anno1(name = "张三")
public class Test {
@Anno1(name = "李四", age = 14)
private @Anno int a;
@Anno
@Anno1(name = "王五")
public void b(){}
}
public @interface Anno {
}
public @interface Anno1 {
String name();
int age() default 0;
}
/*
@Target常用配置
@Target():
*/
@Week
public class Test {
@Week
public Test(int a) {
this.a = a;
}
@Week
private int a;
@Week
private void b(){ }
}
@Target({
ElementType.TYPE,
ElementType.METHOD,
ElementType.CONSTRUCTOR,
ElementType.FIELD})
public @interface Week {
}
/*
1.注解解析相关方法:
Annotation[] getAnnotations() 获取所有注解
<Annotation> T getAnnotation(Class<T> annotationClass) 获取一个指定的注解
boolean isAnnotationPresent(Class<Annotation> annotationClass) 判断是否有指定的注解
2.如何解析注解?
通过反射来解析注解,注解在谁头上就用谁来解析
如果注解在类上,使用Class来获取
如果注解在构造方法上,使用Constructor来获取
如果注解在成员方法上,使用Method来获取
如果注解在成员变量上,使用Field来获取
*/
public class Test {
public static void main(String[] args) throws Exception{
//反射获取show方法
//获取字节码对象
Class<demoBook> clazz = demoBook.class;
//通过字节码对象获取方法
Method met1 = clazz.getMethod("show");
//通过获取的方法去获取注解
Book an = met1.getAnnotation(Book.class);
//判断注解是否存在
boolean ifAnno = met1.isAnnotationPresent(Book.class);
if (ifAnno) {
//操作注解获取属性
System.out.println(an.name());
System.out.println(an.price());
System.out.println(Arrays.toString(an.author()));
}
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String name();
double price();
String[] author();
}
public class demoBook {
@Book(name = "红楼梦", price = 29.9, author = {"曹雪芹", "高鹗"})
public void show() {}
}