Java基础之单元测试和注解学习笔记分享
## Junit单元测试> 测试分类:
>
> * 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
> * 白盒测试:需要写代码的。关注程序具体的执行流程。
![黑盒测试和白盒测试](https://cdn.jsdelivr.net/gh/mobaijun/blog_css_js/image/blog_images/20200623210425.png)
> 什么是单元测试
>
> * 对一部分代码进行测试
## Junit介绍
> Junit是一个Java语言的单元测试框架,属于白盒测试,简单理解为可以用于取代java的main方法。Junit属于第三方工具,需要导入jar包后使用。
>
> 什么是Junit:
>
> * 是第三方写的一个单元测试框架,可以取代main方法
> * Junit需要导入jar包,压缩包,里面有很多的java代码,因为Junit使用广泛,所以idea就已经包含了Junit,只需要引入即可
>
> Junit的好处:
>
> * 可以单独测试一部分代码
>
> Junit的使用步骤:
>
> > * 编写测试类
> >
> > * 编写测试方法:
> >
> > * 必须是public修饰符的
> >
> > * 必须是没有返回值的void
> >
> > * 必须没有参数
> >
> > > public void 方法名() {
> > > 测试代码
> > > }
> >
> > * 给测试方法添加@Test注解
> >
> > * 运行测试方法
> >
> > * 看结果
> >
> > * 绿色:表示通过
> > * 红色:表示失败
## Junit的使用
> * 编写测试类,简单理解Junit可以用于取代java的main方法
> * 在测试类方法上添加注解 @test
> * @Test修饰的方法要求:public void 方法名() {…} ,方法名自定义建议test开头,没有参数。
> * 添加Junit库到lib文件夹中,然后进行jar包关联
> * 使用:点击方法左侧绿色箭头,执行当前方法(方法必须标记@Test)。执行结果红色:代表失败;执行结果 绿色:代表成功
~~~java
package com.mobai;
import org.junit.Test;
import java.util.Arrays;
/**
* Software:IntelliJ IDEA 2020.1 x64
* Author: MoBai·杰
* ClassName:Test
* 类描述:Junit测试
*/
public class TestDemo1 {
@Test
public void test01() {
for (int i = 0; i < 100; i++) {
System.out.println(" i: " + Arrays.class.getClass());
}
}
}
~~~
## 常用注解
> * @Test,用于修饰需要执行的测试方法
> * @Before,修饰的方法会在测试方法之前被自动执行
> * @After,修饰的方法会在测试方法执行之后自动被执行
~~~java
package com.mobai;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
/**
* Software:IntelliJ IDEA 2020.1 x64
* Author: MoBai·杰
* ClassName:Test
* 类描述:Junit测试
*/
public class TestDemo1 {
@Before
public void testBefore() {
System.out.println(" 前置方法 ");
}
@After
public void testAfter() {
System.out.println(" 后置方法 ");
}
@Test
public void test01() {
for (int i = 0; i < 10; i++) {
System.out.println(" i: " + Arrays.class.getClass());
}
}
}
~~~
## Class对象
!(https://cdn.jsdelivr.net/gh/mobaijun/blog_css_js/image/blog_images/20200623230456.png)
> * 当程序需要用到Person类的时候会将Person.class加载到内存中
> * 将Person.class加载到内存,分别存放成员变量,成员方法,构造方法
> * Java虚拟机会主动创建一个Class对象,描述方法区中的Person.class的内容
## 反射的概念
> > 什么是反射?
>
> * 在程序运行的过程中,通过Class对象得到类中构造方法,成员方法,成员变量,并操作他们
>
> > 反射的应用场景
>
> * idea等开发工具的智能提示
> * 开发框架 SSM
>
> > 反射的好处
>
> * 可以在程序运行过程中,操作这些对象。
> * 可以解耦,提高程序的可扩展性。
## 三种获取Class对象的信息
| 获取CLASS对象的方式 | 作用 | 应用场景 |
| ----------------------- | ---------------------------- | --------------------------------------------------------- |
| 类名.class | 通过类名的属性class获取 | 多用来传递参数 |
| Class.forName(“类全名”) | 通过指定的字符串路径获取 | 多用来加载配置文件,将类名定义在配置文件中,读取文件,加载类 |
| 对象.getClass() | 通过对象的getClass()方法获取 | 多用来获取对象的字节码 |
> 三种获取Class对象的方式
>
> * 类名.class
> * 对象名.getClass()
> * Class.forName(类全名)/(类全名就是:包名.类名)
>
> > 注意:这三种方式得到的都是同一个对象
~~~java
/**
* Software:IntelliJ IDEA 2020.1 x64
* Author: MoBai·杰
* ClassName:TestClass
* 类描述: 三种获取Class对象的方式
*/
public class TestClass {
public static void main(String[] args) throws Exception {
// 1.类名.class
Class clz = Book.class;
System.out.println("clz = " + clz);
// 2.通过对象名.getClass()
Book book = new Book();
Class clz2 = book.getClass();
System.out.println("clz2 = " + clz2);
// 3.通过Class.forName(类全名)
Class clz3 = Class.forName("com.mobai.annion.Book");
System.out.println("clz3 = " + clz3);
// 这三种方式得到的都是同一个对象
System.out.println(clz2 == clz3);
System.out.println(clz == clz2);
}
}
~~~
## 获取Class对象的信息
> 常用方法:
| **String getSimpleName();** | 获得简单类名,只是类名,没有包 |
| --------------------------- | ------------------------------------------------------------ |
| **String getName();** | **获得完整类名,包含包名 + 类名** |
| **T newTnstatance();** | 创建此Class对象所表示的类是一个新实例<br />要求:类必须有<public>的无参构造方法 |
~~~java
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
// 1.得到Class对象
Class clazz = Class.forName("com.mobai.annion.Book");
// 2.调用方法getName
String name1 = clazz.getName();
// name1 = com.mobai.annion.Book
System.out.println("name1 = " + name1);
// 2.1调用方法getSimpleName
String name2 = clazz.getSimpleName();
// name2 = Book
System.out.println("name2 = " + name2);
}
}
~~~
## 反射获取public的构造方法
> Constructor类作用:
>
> * 表示类中构造方法
>
> 如何得到public的Constructor对象:
>
> * 获取Class对象
> * 通过Class对象获取构造方法
>
> > cls.getConstructor(); 获取一个public的构造方法
> >
> > cls.getConstructors(); 获取所有public的构造方法
>
> * Constructor类的方法:
>
> * newInstance(); 创建对象
>
> * 基本数据类型与引用数据类型的Class对象
>
> > int.class != Integer.class
* 创建一个学生类
~~~java
/**
* Software:IntelliJ IDEA 2020.1 x64
* Author: MoBai·杰
* ClassName:Student
* 类描述: 学生类
*/
public class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Student(String name) {
this.name = name;
}
public Student(Integer age) {
this.age = age;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
~~~
* 测试类
~~~java
public class TestDemo1 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.mobai.fanshe.Student");
// 1.获取所有public的构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("constructor = " + constructor);
}
// 2.获取一个public构造方法
Constructor<?> constructors1 = clazz.getConstructor();
// public com.mobai.fanshe.Student()
System.out.println("constructors1 = " + constructors1);
// 2.1反射获取指定的构造方法
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
// public com.mobai.fanshe.Student(java.lang.String,java.lang.Integer)
System.out.println("constructor = " + constructor);
}
}
~~~
## 反射通过Constructor创建对象
~~~java
public class TestDemo1 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.mobai.fanshe.Student");
// 1.获取所有public的构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("constructor = " + constructor);
}
// 2.获取一个public构造方法
Constructor<?> constructors1 = clazz.getConstructor();
// public com.mobai.fanshe.Student()
System.out.println("constructors1 = " + constructors1);
// 2.1反射获取指定的构造方法
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
// public com.mobai.fanshe.Student(java.lang.String,java.lang.Integer)
System.out.println("constructor = " + constructor);
// 3.使用newInstance创建对象
Object instance = constructor.newInstance("墨白君", 15);
// Student{name='墨白君', age=15}
System.out.println("instance = " + instance);
}
}
~~~
## 反射获取声明的构造方法
> 声明的Constructor就是类中有的构造方法,不管权限
>
> 如何得到声明的Constructor:
>
> * 得到Class对象
> * 通过Class对象得到声明Constructor
>
> > Declared的规律:
> >
> > * cls.getConstructor();获取一个public的构造方法
> > * cls.getConstructors();获取所有public的构造方法
> > * cls.getDeclaredConstructors(); 得到所有声明的构造方法
> > * cls.getDeclaredConstructor(); 得到一个声明的构造方法
> > * 没有Declared是得到public的
> > * 有Declared是得到声明的
> > * 没有s的是得到一个
> > * 有s的是得到多个
>
> 对私有构造方法我们在使用之前调用
>
> * con.setAccessible(true); 暴力反射
* 学生类
~~~java
public class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Student(String name) {
this.name = name;
}
private Student(Integer age) {
this.age = age;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
~~~
* 测试类
~~~java
public class TestDemo2 {
public static void main(String[] args) throws Exception {
// 1.获取Class对象
Class<?> clazz = Class.forName("com.mobai.fanshe.Student");
// 2.得到一个申明的构造方法
Constructor<?> constructor = clazz.getDeclaredConstructor(Integer.class);
// private com.mobai.fanshe.Student(java.lang.Integer)
System.out.println("constructor = " + constructor);
// 暴力反射
constructor.setAccessible(true);
// 创建对象
Object instance = constructor.newInstance(16);
System.out.println("instance = " + instance);
}
}
~~~
## Class的newInstance方法创建对象
> Class的newInstance方法就是使用无参构造创建对象.
~~~java
public class TestDemo3 {
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("com.mobai.fanshe.Student");
// 获取无参构造
Constructor<?> constructor = clazz.getConstructor();
// 通过无参构造创建对象
Object instance = constructor.newInstance();
// instance = Student{name='null', age=null}
System.out.println("instance = " + instance);
// Class对象创建对象的方法
Student instance1 = (Student) clazz.newInstance();
// instance1 = Student{name='null', age=null}
System.out.println("instance1 = " + instance1);
}
}
~~~
## 反射获取Method
> * Method类作用
> * 表示类中的方法
>
> * 如何得到Method对象
> * 得到Class对象
> * 通过Class对象获取Method
> * cls.getMethods(); 获取所有public的方法
> * cls.getMethod(); 获取一个public的方法
> * cls.getDeclaredMethods(); 获取所有声明的方法
> * cls.getDeclaredMethod(); 获取一个声明的方法
>
> * Method类中的方法: 得到Method就可以调用这个方法
> * Object invoke(Object target, Object... args);
> * Object target: 调用方法的对象
> * Object... args: 调用方法时传递的参数
> * Object: 返回值类型
* 学生类
~~~java
public class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Student(String name) {
this.name = name;
}
private Student(Integer age) {
this.age = age;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
~~~
* 通过class获取所有方法
~~~java
public class TestDemo4 {
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("com.mobai.fanshe.Student");
// 通过CLass获取方法
Method[] methods = clazz.getMethods();
// 遍历获取所有public方法
for (Method method : methods) {
System.out.println("method = " + method);
}
// 获取一个方法
Method setName = clazz.getMethod("setName", String.class);
// setName = public void com.mobai.fanshe.Student.setName(java.lang.String)
System.out.println("setName = " + setName);
// 获取所有声明的方法
Method[] methods1 = clazz.getDeclaredMethods();
for (Method method : methods1) {
System.out.println("method = " + method);
}
// 获取一个声明的方法
Method getName = clazz.getDeclaredMethod("getName");
// public java.lang.String com.mobai.fanshe.Student.getName()
System.out.println("getName = " + getName);
}
}
~~~
## 什么是注解?
> > **注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、 接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。**
>
> * **Annotnation的作用:**
> * **说明程序的,给计算机解释**
> * **可以被其他程序读取**
> * **Annotnation的格式**
> * **注解是以"@注解名称"在代码中存在的,还可以添加一些参数**
> * **Annotnation在哪里使用?**
> * **可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息,可以通过反射机制编程实现对这些元数据的访问**
>
> * **作用分类:**
> * **编写文档:通过代码里标识的注解生成文档【生成文档doc文档】**
> * **代码分析:通过代码里标识的注解对代码进行分析【使用反射】**
> * **编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】**
> * **常见注解:**
> * **@author:用来标识作者名,eclipse开发工具默认的是系统用户名。**
> * **@since:从那个版本开始**
> * **@version:用于标识对象的版本号,适用范围:文件、类、方法。**
> * **@Override:用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。**
## 自定义注解
> **自定义注解: 注解本质上就是一个接口,该接口默认继承Annotation接口**
>
> ~~~java
> public interface MyAnno extends java.lang.annotation.Annotation {}
> ~~~
* **自定义注解**
~~~java
// 空注解
public @interface Anno01 {
}
~~~
* **有参数的注解**
> **只能使用Java提供的基本数据类型,String可以,Class可以,枚举类,其他暂未测试,包装类不可以.自定义类不可以**
~~~java
public @interface Anno02 {
// 属性
String name();
double price() default 99;
String[] authors();
// Anno01 abc(); // 注解
// WeekDay w();
// Class p();
}
enum WeekDay {
SUN, MON
}
class Person {
}
~~~
## 注解的属性类型
> * 八种基本数据类型
> * String,注解,枚举,Class
> * 以上类型的一维数组
>
> > 自定义类不可以
## 使用自定义注解
> * **注解可以用来保存数据**
>
> * **使用自定义注解格式:**
>
> > @注解名(属性名=属性值, 属性名=属性值)
>
> 注意:注解的属性可以有默认值,当使用注解时不赋值就使用默认值,赋值就按照赋的值
* **定义注解**
~~~java
package com.mobai.annaction;
// 自定义注解
public @interface MoBai {
// 名字
String name();
// 默认属性
String value() default "框架师";
}
~~~
* **使用注解**
~~~java
public class AnnactionTest {
@MoBai(name = "墨白",value = "")
public static void main(String[] args) {
}
@Test
public void annTest(){
}
}
~~~
## 自定义注解的特殊情况
> **当注解只有一个属性,并且属性名是value时,在使用注解时可以省略属性名**
* **自定义注解**
~~~java
public @interface MoBai {
String value();
}
~~~
* **使用注解**
~~~java
@MoBai("abc")
public class Demo11 {
@MoBai(value = "abc")
public static void main(String[] args) {
}
}
~~~
## 元注解
> * **@Target**
> * **@Retention**
>
> > **修饰注解的注解叫做元注解**
#### @Target元注解:
> * **默认情况注解可以放在任意位置**
>
> > * **限制注解可以放在哪些位置**
> > * **@Target(ElementType.TYPE) 注解只能放在类或者接口上**
> > * **@Target(ElementType.CONSTRUCTOR) 注解只能放在构造方法上**
> > * **@Target(ElementType.FIELD) 注解只能放在成员变量上**
> > * **@Target(ElementType.METHOD) 注解只能放在成员方法上**
> > * **@Target(ElementType.LOCAL_VARIABLE) 注解只能放在局部变量上**
#### @Retention元注解:
> * **默认是CLASS阶段**
>
> > * **限制注解可以活到什么时候**
> >
> > > * **SOURCE = = = = = = = = = = >>CLASS = = = = = = = = = = = = = >>RUNTIME**
> > > * **源代码阶段(.java) = = = = >>编译 = = = >>.class = = = = = = >>运行**
* **自定义注解**
~~~java
//@Target(ElementType.TYPE) // 注解只能放在类或者接口上
//@Target(ElementType.CONSTRUCTOR) // 注解只能放在构造方法上
//@Target(ElementType.FIELD) // 注解只能放在成员变量上
//@Target(ElementType.METHOD) // 注解只能放在成员方法上
//@Target(ElementType.LOCAL_VARIABLE) // 注解只能放在局部变量上
@Retention(RetentionPolicy.RUNTIME)
public @interface MoBai {
}
~~~
* **使用注解**
~~~java
@MoBai
public class Demo12 {
@MoBai
private String a;
@MoBai
public Demo12() {
}
@MoBai
public static void main(String[] args) {
@MoBai
int x = 10;
}
}
~~~
## 注解的解析
> * **什么是注解解析?**
>
> > **获取注解中保存的数据**
>
> * **注解解析相关接口?**
>
> > * **AnnotatedElement接口中:**
> >
> > * **Annotation getAnnotation(Class<T> annotationClass) 获取一个注解**
> >
> > * **Annotation[] getAnnotations()获取多个注解**
> >
> > * **boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判断有没有指定的注解**
> >
> > > **注意: Constructor , Field , Method实现了AnnotatedElement接口**
>
> * **如何解析注解?**
>
> > * **注解在谁头上,就用谁来获取注解**
> > * **注解在构造方法上,使用Constructor对象获取注解**
> > * **注解在成员方法上,使用Method对象获取注解**
> > * **注解在成员变量上,使用Field对象获取注解**
> > * **使用反射**
* **创建自定义注解**
~~~java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Software:IntelliJ IDEA 2020.1 x64
* Author: MoBai·杰
* [@]Interface:MoBook
* 注解描述: 自定义注解
*/
// 限定方法使用
@Target(ElementType.METHOD)
// 活到运行时候
@Retention(RetentionPolicy.RUNTIME)
public @interface MoBook {
String name();
double price();
String[] authors();
}
~~~
* **定义数据类使用注解**
~~~java
/**
* Software:IntelliJ IDEA 2020.1 x64
* Author: MoBai·杰
* ClassName:Book
* 类描述: 书籍类
*/
public class Book {
@MoBook(name = "框架师", price = 25.0, authors = "墨白")
public void sell() {
}
}
~~~
* **测试类**
~~~java
public class TestMoBook {
public static void main(String[] args) throws Exception {
// 1.获取Class对象
Class<?> className = Class.forName("com.mobai.annion.Book");
// 2.获取Method对象
Method method = className.getMethod("sell");
// 3.通过method对象获取注解
Annotation[] annotations = method.getAnnotations();
// 4.遍历数组
for (Annotation annotation : annotations) {
System.out.println("annotation = " + annotation);
}
// 3.3 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
//判断有没有指定的注解
boolean b = method.isAnnotationPresent(MoBook.class);
System.out.println(b);
if (b) {
// 3.2 Annotation getAnnotation(Class<T> annotationClass) 获取一个注解
MoBook ann = method.getAnnotation(MoBook.class);
System.out.println(ann.name() + "::" + ann.price() + "::" + Arrays.toString(ann.authors()));
}
}
}
~~~ 好,学习了 多学分享 祝你早日秀发飘飘 最近在学这方面的,先收藏了 mk下,正在转java...
页:
[1]