第一节 Junit单元测试
测试分类:
1、黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望值
2、白盒测试:需要写代码,关注程序具体的执行流程
Junit使用:白盒测试
使用步骤:
1、定义一个测试类
建议:测试类名:被测试的类名Test
包名:XXX.XX.XX.test
2、定义测试方法:可以独立运行
建议:方法名:test测试的方法名
返回值:void
参数列表:空参
3、给方法加注解@Test
4、导入junit依赖环境
判断结果:
红色:代表失败
绿色:代表成果
一般会使用断言操作来处理结果
Assert.assertEquals(期望的结果, 运算的结果);
//计算器类
public class Calculator {
public int add(int a, int b){
return a + b;
};
public int sub(int a, int b){
return a - b;
}
}
import Demo01.Junit.Calculator;
import org.junit.Assert;
import org.junit.Test;
public class CalculatorTest {
//测试add方法
@Test
public void testAdd(){
//System.out.println("我被执行了");
Calculator c = new Calculator();
int result = c.add(1, 2);
//System.out.println(result);
//断言 我断言这个结果是3
Assert.assertEquals(3, result);
}
//测试sub方法
@Test
public void testSub(){
Calculator c = new Calculator();
int result = c.sub(3, 2);
Assert.assertEquals(1,result);
}
}
初始化方法:
用于资源申请,所有测试方法在执行之前都会先执行该方法
释放资源方法:
在所有测试方法执行完毕后,都会自动执行该方法
@Before
public void init(){
System.out.println("init...");
}
@After
public void close(){
System.out.println("close...");
}
第二节 反射
反射:框架设计的灵魂
框架:半成品软件,可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装为其他对象,这就是反射机制
好处:
1、可以在程序运行过程中,操作这些对象
2、可以解耦,提高程序的可扩展性
2.1 获取Class类对象的方式
1、Class.forName(“全类名”):将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2、类名.class:通过类名的属性class获取
多用于参数的传递
3、对象.getClass():getClass()方法在Object类中定义
多用于对象的获取字节码的方式
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
public class ReflectDemo01 {
public static void main(String[] args) throws ClassNotFoundException {
//Class.forName("全类名")
Class cls = Class.forName("Demo01.domain.Person");
System.out.println(cls);
//类名.class
Class cls2 = Person.class;
System.out.println(cls2);
//对象.getClass()
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3);
//比较三个对象 ==
System.out.println(cls == cls2);//true
System.out.println(cls == cls3);//true
}
}
2.2 使用Class类对象
Class对象功能:
1、获取功能
获取成员变量们
获取构造方法们
获取成员方法们
获取类名
//获取成员变量们
public class ReflectDemo02 {
public static void main(String[] args) throws Exception {
Class personClass = Person.class;
//getFields()获取所有public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
//getField(String name)
Field a = personClass.getField("a");
//获取成员变量a的值
Person p = new Person();
Object value = a.get(p);
System.out.println(value);//null
//设置a的值
a.set(p,"小松狮");
System.out.println(p);
System.out.println("==========");
//getDeclaredFields()获取所有的成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//getDeclaredField(String name)
Field d = personClass.getDeclaredField("d");
//忽略访问权限修饰符的安全检查
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);//null
}
}
//获取构造方法们
public class ReflectDemo03 {
public static void main(String[] args) throws Exception {
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//创建对象newInstance方法
Object person = constructor.newInstance("小松狮", 19);
System.out.println(person);
System.out.println("=======");
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//创建对象newInstance方法
Object person1 = constructor1.newInstance();
System.out.println(person1);
//如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
Object o = personClass.newInstance();
System.out.println(o);
}
}
//获取成员方法们
public class ReflectDemo04 {
public static void main(String[] args) throws Exception {
Class personClass = Person.class;
//获取指定名称的方法getMethod
Method eat_method = personClass.getMethod("eat");
Person p = new Person();
eat_method.invoke(p);
Method eat_method1 = personClass.getMethod("eat", String.class);
eat_method1.invoke(p,"饭饭");
//获取所有public修饰的方法getMethods()
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
//获取方法名getName()
String name = method.getName();
System.out.println(name);
}
//获取全类名
String name = personClass.getName();
System.out.println(name);
}
}
2.3 案例
需求:写一个“框架”,不能改变该类的任何代码前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
实现:
1、配置文件
2、反射
步骤:
1、将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2、在程序中加载读取配置文件
3、使用反射技术来加载类文件进内存
4、创建对象
5、执行方法
配置文件
className=Demo01.domain.Student
methodName=sleep
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
//框架类
public class ReflectTest {
public static void main(String[] args) throws Exception{
/*
前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
*/
/*Person p = new Person();
p.eat();*/
/*Student s = new Student();
s.sleep();*/
//1、加载配置文件
//1.1 创建Properties对象
Properties prop = new Properties();
//1.2 加载配置文件,转换为一个集合
//1.2.1 获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
prop.load(is);
//2、获取配置文件中定义的数据
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
//3、加载该类进内存
Class cls = Class.forName(className);
//4、创建对象
Object obj = cls.newInstance();
//5、获取方法对象
Method method = cls.getMethod(methodName);
//6、执行方法
method.invoke(obj);
}
}
第三节 注解
注释:用文字描述程序的,给程序员看的
注解:说明程序的,给计算机看的
概念描述:JDK1.5之后的新特性,说明程序的,使用注解:@注解名称
JDK中预定义的一些注解
@Override:检测被该注解标注的方法是否是继承自父类(接口)的
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告,一般传递参数all,@SuppressWarnings(“all”)
@SuppressWarnings("all")
public class AnnoDemo01 {
@Override
public String toString(){
return super.toString();
}
@Deprecated
public void show1(){
//有缺陷
}
public void show2(){
//替代show1方法
}
public void demo(){
show1();
show2();
}
}
3.1 自定义注解
/*
自定义注解
格式:
元注解
public @interface 注解名称{
属性列表
}
本质:注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation{}
属性:接口中可以定义的抽象成员方法
要求:
1、属性的返回值类型:基本数据类型、String、枚举、注解、以上类型的数组
2、定义了属性,在使用时要给属性赋值
(1)如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不进行属性的赋值
(2)如果只有一个属性需要赋值,并且属性的名称时value,则value可以省略,直接定义值即可
(3)数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}省略
元注解:用于描述注解的注解
@Target:描述注解能够作用的位置
ElementType取值:
TYPE:可以作用于类上
METHOD:可以作用于方法上
FIELD:可以作用于成员变量上
@Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解会保留到class字节码文件中,并被JVM读取到
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承
*/
public @interface MyAnno {
int value();
String name() default "小松狮";//默认取值
}
@MyAnno(18)
public class Person {
}
import java.lang.annotation.*;
@Target(value = {ElementType.TYPE})//表示该MyAnno3注解只能作用于类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnno3 {
}
3.2 解析注解
/*
在程序中使用(解析)注解:获取注解中定义的属性值
1、获取注解定义的位置的对象(Class,Method,Field)
2、获取指定的注解
getAnnotation(Class)
3、调用注解中的抽象方法获取注解的配置属性值
*/
public class Demo1 {
public void show(){
System.out.println("demo1...show...");
}
}
/*
描述需要执行的类名和方法名
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
String className();
String methodName();
}
import java.lang.reflect.Method;
@Pro(className = "Day20.Demo01.Demo1",methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws Exception{
/*
前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
*/
//解析注解,获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//获取注解对象
Pro annotation = reflectTestClass.getAnnotation(Pro.class);
String className = annotation.className();
String methodName = annotation.methodName();
System.out.println(className);
System.out.println(methodName);
//3、加载该类进内存
Class cls = Class.forName(className);
//4、创建对象
Object obj = cls.newInstance();
//5、获取方法对象
Method method = cls.getMethod(methodName);
//6、执行方法
method.invoke(obj);
}
}
3.3 异常测试案例
//定义的计算器类
public class Calculator {
@Check
public void add(){
System.out.println("1 + 0 = " + (1 + 0) );
}
@Check
public void sub(){
System.out.println("1 - 0 = " + (1 - 0) );
}
@Check
public void mul(){
System.out.println("1 * 0 = " + (1 * 0) );
}
@Check
public void div(){
System.out.println("1 / 0 = " + (1 / 0) );
}
public void show(){
System.out.println("无Bug!");
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestCheck {
public static void main(String[] args) throws IOException {
//创建计算器类对象
Calculator calculator = new Calculator();
//获取字节码文件对象
Class aClass = calculator.getClass();
//获取所有方法
Method[] methods = aClass.getMethods();
int number = 0;//出现异常的次数
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
if (method.isAnnotationPresent(Check.class)){
try {
method.invoke(calculator);
} catch (Exception e) {
number++;
bw.write(method.getName() + "方法出异常了");
bw.newLine();
bw.write("异常的名称:" + e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因:" + e.getCause().getMessage());
bw.newLine();
bw.write("---------------");
bw.newLine();
}
}
}
bw.write("本次测试出现了" + number + "次异常");
bw.flush();
bw.close();
}
}