Junit单元测试
测试分类:
- 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
- 白盒测试:需要写代码的。关注程序具体的执行流程。
什么是单元测试
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)。执行结果红色:代表失败;执行结果 绿色:代表成功
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,修饰的方法会在测试方法执行之后自动被执行
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对象
- 当程序需要用到Person类的时候会将Person.class加载到内存中
- 将Person.class加载到内存,分别存放成员变量,成员方法,构造方法
- Java虚拟机会主动创建一个Class对象,描述方法区中的Person.class的内容
反射的概念
> 什么是反射?
- 在程序运行的过程中,通过Class对象得到类中构造方法,成员方法,成员变量,并操作他们
> 反射的应用场景
> 反射的好处
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
三种获取Class对象的信息
获取CLASS对象的方式 |
作用 |
应用场景 |
类名.class |
通过类名的属性class获取 |
多用来传递参数 |
Class.forName(“类全名”) |
通过指定的字符串路径获取 |
多用来加载配置文件,将类名定义在配置文件中,读取文件,加载类 |
对象.getClass() |
通过对象的getClass()方法获取 |
多用来获取对象的字节码 |
三种获取Class对象的方式
- 类名.class
- 对象名.getClass()
- Class.forName(类全名)/(类全名就是:包名.类名)
> 注意:这三种方式得到的都是同一个对象
/**
* 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>的无参构造方法 |
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的构造方法
/**
* 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 +
'}';
}
}
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创建对象
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); 暴力反射
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 +
'}';
}
}
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方法就是使用无参构造创建对象.
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
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 +
'}';
}
}
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接口
public interface MyAnno extends java.lang.annotation.Annotation {}
// 空注解
public @interface Anno01 {
}
只能使用Java提供的基本数据类型,String可以,Class可以,枚举类,其他暂未测试,包装类不可以.自定义类不可以
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
- 以上类型的一维数组
> 自定义类不可以
使用自定义注解
-
注解可以用来保存数据
-
使用自定义注解格式:
> @注解名(属性名=属性值, 属性名=属性值)
注意:注解的属性可以有默认值,当使用注解时不赋值就使用默认值,赋值就按照赋的值
package com.mobai.annaction;
// 自定义注解
public @interface MoBai {
// 名字
String name();
// 默认属性
String value() default "框架师";
}
public class AnnactionTest {
@MoBai(name = "墨白",value = "")
public static void main(String[] args) {
}
@Test
public void annTest(){
}
}
自定义注解的特殊情况
当注解只有一个属性,并且属性名是value时,在使用注解时可以省略属性名
public @interface MoBai {
String value();
}
@MoBai("abc")
public class Demo11 {
@MoBai(value = "abc")
public static void main(String[] args) {
}
}
元注解
> 修饰注解的注解叫做元注解
@Target元注解:
@Retention元注解:
> 限制注解可以活到什么时候
>
> > SOURCE = = = = = = = = = = >>CLASS = = = = = = = = = = = = = >>RUNTIME
> > * 源代码阶段(.java) = = = = >>编译 = = = >>.class = = = = = = >>运行
//@Target(ElementType.TYPE) // 注解只能放在类或者接口上
//@Target(ElementType.CONSTRUCTOR) // 注解只能放在构造方法上
//@Target(ElementType.FIELD) // 注解只能放在成员变量上
//@Target(ElementType.METHOD) // 注解只能放在成员方法上
//@Target(ElementType.LOCAL_VARIABLE) // 注解只能放在局部变量上
@Retention(RetentionPolicy.RUNTIME)
public @interface MoBai {
}
@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对象获取注解
> * 使用反射
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();
}
/**
* Software:IntelliJ IDEA 2020.1 x64
* Author: MoBai·杰
* ClassName:Book
* 类描述: 书籍类
*/
public class Book {
@MoBook(name = "框架师", price = 25.0, authors = "墨白")
public void sell() {
}
}
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()));
}
}
}