Junit单元测试
测试分类:
1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
2. 白盒测试:需要写代码的。关注程序具体的执行流程。
测试就是对所完成功能的校验,查看功能是否有缺陷有漏洞。在工作中,每次做完功能后都要进行测试,测试通过才可以结束该功能的编写。测试是开发中很重要的一部分。
测试前提
进行单元测试时,一定先要引入Junit包才可以使用。并且@Test该注解必须在方法名上;
@BeforeClass:针对所有测试,只执行一次,且必须为static void
@Before:初始化方法 (一般用于申请资源,为后续的方法初始化一些环境)
@Test:测试方法,在这里可以测试期望异常和超时时间
@After:释放资源
@AfterClass:针对所有测试,只执行一次,且必须为static void
@Ignore:忽略的测试方法
一个单元测试用例执行顺序为: @BeforeClass –> @Before –> @Test –> @After –> @AfterClass
每一个测试方法的调用顺序为: @Before –> @Test –> @After
public class TestCal {
@BeforeClass
public static void init() {
System.out.println("init...");
}
@Before
public void beforeMethod() {
System.out.println("beforeMethod...");
}
@Test
public void testCal(){
Calculator c = new Calculator();
int result =c.cal(10,10);
// 这个方法叫断言,既我断言这个代码的执行结果result是1,如果断言
// 正确则控制台绿色√,否则共色×
Assert.assertEquals(1,result);
}
@After
public void afterMethod() {
System.out.println("afterMethod...");
}
@AfterClass
public static void after() {
System.out.println("after...");
}
}
输出结果为:
init...
beforeMethod...
afterMethod...
after...
反射
定义:将类的各个组成部分封装为其他对象,这就是反射机制。
好处:
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射_获取字节码Class对象的三种方式
-
Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象;
-
类名.class:通过类名的属性class获取;
-
对象.getClass():getClass()方法在Object类中定义着。
注意:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。1. 获取成员变量们 * Field[ ] getFields() :获取所有public修饰的成员变量 * Field getField(String name) 获取指定名称的 public修饰的成员变量 * Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符 * Field getDeclaredField(String name) 2. 获取构造方法们 * Constructor<?>[] getConstructors() * Constructor<T> getConstructor(类<?>... parameterTypes) * Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors() 3. 获取成员方法们: * Method[] getMethods() * Method getMethod(String name, 类<?>... parameterTypes) * Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 类<?>... parameterTypes) 4. 获取全类名 * String getName()
public class ReflectDemo {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
Class<Person> person=Person.class;//获取一个Person类的class对象
System.out.println(person);//class java_reflect.Person
//首先获取成员变量对象,然后获取内部的每一个变量名
Field[] fields=person.getDeclaredFields();
for (Field field : fields) {//使用了declared,表示获取所有的成员变量
System.out.println(field.getType()+" "+field.getName());
}
/**
* 这是输出结果
* class java.lang.String name
int age
int score
*/
System.out.println("=======================");
//返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
//也就是说整个返回的对象包含了该类的指定参数的构造函数对象
Constructor<Person> con=person.getConstructor(String.class);
System.out.println(con.getName()+"构造函数可接受的参数个数:"+con.getParameterCount());
//输出:java_reflect.Person构造函数可接受的参数个数:1
System.out.println("=======================");
//这个是获取的person对象的所有权限等级的方法,但不包括超类的,返回
//一个方法数组
Method[] methods=person.getDeclaredMethods();
for (Method method : methods) {
System.out.println("方法修饰符:"+Modifier.toString(method.getModifiers()));
System.out.println("方法名:"+method.getName());
//需要遍历这个参数类型的数组,然后得到每一个参数的类型getType()
System.out.println("方法参数:"+method.getParameters());
System.out.println("方法参数个数:"+method.getParameterCount());
System.out.println("----------------------------");
}
}
}
注解
定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
注解就是为了简化开发,避免写过多的代码,不利于程序的扩展以及维护。
JDK中预定义的一些注解
@Override
限定重写父类方法。对于子类中被@Override 修饰的方法,如果存在对应的被重写的父类方法,则正确;如果不存在,则报错。@Override 只能作用于方法,不能作用于其他程序元素。
@Deprecated
用于表示某个程序元素(类、方法等)已过时。如果使用了被@Deprecated修饰的类或方法等,编译器会发出警告。
@SuppressWarnings
抑制编译器警告。指示被@SuppressWarnings修饰的程序元素(以及该程序元素中的所有子元素,例如类以及该类中的方法…)取消显示指定的编译器警告。例如,常见的@SuppressWarnings(value=“unchecked”)
SuppressWarnings注解的常见参数值的简单说明:
- deprecation:使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告);
- unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告
- fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
- path:在类路径、源文件路径等中有不存在的路径时的警告;
- serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
- finally:任何 finally 子句不能正常完成时的警告;
- all:关于以上所有情况的警告。
元注解
元注解:用于描述注解的注解
- @Target:描述注解能够作用的位置
- ElementType取值(@Target接口的方法,但更像是一种属性写法):
- TYPE:可以作用于类上
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
- ElementType取值(@Target接口的方法,但更像是一种属性写法):
- @Retention:描述注解被保留的阶段
- @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
- @Documented:描述注解是否被抽取到api文档中
- @Inherited:描述注解是否被子类继承
1.@Retention: 定义注解的保留策略
- @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
- @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
- @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
首 先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
接下来写个小demo,首先自定义一个注解@Check,然后写一个类,类中定义了很多方法,如果方法上带有@Check这个注解,我们就执行他,如果错误就生成日志信息。
// 自定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}
// 写一个类,类中有一些方法,并带有@Check注解
public class Calculator {
@Check
public void add() {
System.out.println("1+0="+(1+0));
}
@Check
public void div() {
System.out.println("1/0="+(1/0));
}
}
public class Demo {
public static void main(String[] args) throws IOException {
Calculator c=new Calculator();// 获取相应的实体类,也可以用Class.forName(“全限定类名”)的方式来生成实例对象
Class<?> claClass=c.getClass();
Method[] methods=claClass.getMethods();// 反射出其中的方法们
int count=0;
// 运用IO流
BufferedWriter bw=new BufferedWriter(new FileWriter("D:/file/d.txt"));
for (Method method : methods) {
// 遍历方法们,如果该方法带有相应注解,则
if (method.isAnnotationPresent(Check.class)) {
try {
// 调用该方法
method.invoke(c);
} catch (Exception e) {
count++;
// 错误就打印日志信息
bw.write("方法名称"+method.getName());
bw.newLine();
bw.write("异常名称"+e.getCause().getClass().getName());
bw.newLine();
bw.write("异常内容"+e.getCause().getMessage());
bw.newLine();
bw.write("这是第"+count+"条异常");
bw.write("--------------------------------");
bw.newLine();
}
}
}
// 释放资源
bw.close();
}
}