#Junit单元测试
- 测试分类
- 黑盒测试:不需要写代码,给输入值,看程序时候能够输出期望的值
- 白盒测试:需要写代码,关注程序具体的执行流程
- Junit使用步骤:白盒测试
步骤
- 定义一个测试类(测试用例)
- 定义测试方法,可以独立运行
- 方法不是主方法独立运行需要加@Test
- 需要导入Junit依赖
判定结果
红色失败,绿色成功
一般会使用断言处理结果
Assert.assertEquals(3,result);
package junit;
public class Caculator {
//加法
public int add(int a ,int b ){
// int i = 3/0;//java.lang.ArithmeticException: / by zero
return a-b;
}
}
package test;
import junit.Caculator;
import org.junit.Assert;
import org.junit.Test;
public class test {
@Test
public void testAdd(){
System.out.println("我被执行了");
//创建计计算方法对象并且调用方法
Caculator a = new Caculator();
int result = a.add(1,2);
//System.out.println(result);
//3.断言,我断言这个的结果是3
Assert.assertEquals(期望的结果,运算的结果);
}
}
- @Before:修饰的方法会在测试方法前自动执行
- @After:修饰的方法会在测试的方法执行之后自动被执行
package test;
import junit.Caculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class test {
/*
初始化方法
用于资源申请,所有测试方法在执行前都会先执行该方法
*/
@Before
public void inti(){
System.out.println("init...");
}
/*
释放资源方法
在所有测试方法执行完后,都会自动执行该方法
*/
@After
public void close(){
System.out.println("close");
}
@Test
public void testAdd(){
System.out.println("我被执行了");
//创建计计算方法对象并且调用方法
Caculator a = new Caculator();
int result = a.add(1,2);
//System.out.println(result);
//3.断言,我断言这个的结果是3
Assert.assertEquals(3,result);
System.out.println("testAdd...");
}
}
反射
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EABKCwBI-1633952857689)(C:\Users\ASUS\Desktop\a.png)]
- 反射:框架设计的灵魂
- 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
- 反射:将类的各个部分封装为其他对象,这就是反射机制
- 好处
- 可以在程序运行过程中,操作这些对象
- 可以解耦,提高程序的可扩展性
- 获取class的三种方式
- Class.forName(“全类名”):将字节码文件加载进入内存,返回class对象:多用于配置文件
- 类名.class:通过类名的属性class获取:多用于参数传递
- 对象.getclass():getClass()方法在Object类中定义着:多用于对象获取字节码的方式
- 结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的class对象都是同一个
class对象功能
- 获取功能
- 获取成员变量们
Field[] getFields():获取public修饰的
Field getFiled(String Name):获取public修饰的
Field[] getDeclaredFields():
Field getDeclasedField(String Name)
操作:
- 设置值:void set(Object obj,Object value)
- 获取值: void get(Object obj)
package Demo1;
public class Person {
public String a;
protected int b ;
int c ;
private int d;
public int age ;
public String name ;
public Person(){ }
public Person(String name ,int age ){
this.name = name ;
this.age = age;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
public int getD() {
return d;
}
public void setD(int d) {
this.d = d;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
package Demo1;
import java.lang.reflect.Field;
public class Demo1 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
//获取Person的class对象
Class Person = Person.class;
//获取成员变量们
// Field[] getFields()
//
// Field getFiled(String Name)
//
// Field[] getDeclaredFields()
//
// Field getDeclasedField(String Name)
Field[] fields = Person.getFields();
for(Field field: fields){
System.out.println(field);
}
System.out.println("------------");
Field a = Person.getField("a");
//获取a的值
Person p = new Person();
Object value = a.get(p);
System.out.println(value);
//设置a
a.set(p,"pofen");
System.out.println(p);
//获取所有的成员变量,不考虑public修饰Field[] getFields()
//Field getDeclasedField(String Name)
Field[] declaredFileds = Person.getDeclaredFields();
for(Field declaredField : declaredFileds){
System.out.println(declaredField);
}
//Field getDeclaredFiled(String name )
Field d = Person .getDeclaredField("d");
//忽略访问权限修饰符的安全检查
d.setAccessible(true);//暴力反射
Object val2 = d.get(p);
System.out.println(val2);
}
}
获取构造方法们
Constructor<?>[] getConstructors()
ConstructorgetConstructor(类<?>…parameterTypes)
Constructor<?>[] getDeclearConstructors()
ConstructorgetDeclearConstructor(类<?>…parameterTypes)
- Constructor:构造方法
创建对象
-
T newInstance(Object…initargs)
-
如果使用空参构造方法创建对象,操作可以简化:class对象的newInstance方法
-
获取成员方法们
Method<?>[] getMethod()
MethodrgetMethod(类<?>…parameterTypes)
Method<?>[] getDeclearMethods()
MethodgetDeclearMethod(类<?>…parameterTypes)
- 获取类名
String getNmae()
注解
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
注解概念描述
- jdk1.5之后的新特性
- 说明程序的
- 使用注解:@注解名称
作用分类
- 编写文档:通过代码里面标识的注解生成文档(生成doc文档)
- 代码分析:通过代码里面的表示注解对代码进行分析(使用反射)
- 编译检查:通过代码里面标识的注解让编译器能够实现基本的编译检查(Override)
- 自定义注解:public @interface 注解名称{属性列表;}
格式:元注解:public @interface 注解名称{}
元注解:描述注解的注解:
@Target:描述注解能够作用的文字
ElementType取值
- TYPE:可以作用于类上
- MHETHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
@Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会被保留到class字节码文件中,并会被JVM读取到
@Doucumented:描述注解是否被走抽取到api中
@Inherited:描述注解是否被子类继承
本质:注解本质就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation{}
属性:接口中可以定义的成员方法
属性要求:
- 属性的返回值类型有下列取值
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
- 如果定义了属性,在使用的时候需要给属性赋值
- 如果定义属性是,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,字节定义值即可
- 、数组赋值时,值需要用{}包裹,如果数组只有一个值,则{}可以省略
- jdk中预定的一些注解
java提供了5个基本的注解,分别是
1.@Override:检测被该注解标注的方法是否继承父类
2.@Deprecated:将该注解标注的内容已过时
3.@SuppressWarnings:压制警告,一般传递参数@SuppressWarnings(“all”)
4.@SafeVarargs
5.@FunctionalInterface
- 在程序中使用(解析)注解:获取注解中定义的属性值
-
获取注解定义的位置的对象(class,method,field)
-
获取指定的注解:getAnnotation(class)
//其实就是在内存中生成了一个该注解接口与的子类实现对象
public class ProImpl implements pro(){
public String className(){
return"Demo1";
}
public String methodName(){
return “show”;
}
}
- 调用注解中的抽象方法获取配置的属性值
package Demo2;
import java.util.Date;
public class AnnoDemo2 {
@Override
public String toString(){return super.toString();}
@Deprecated
public void show1(){
//有缺席
}
public void show2(){
//代替show1方法
}
public void Demo(){
show1();
Date date = new Date();
}
}
package Demo2;
public class Demo1 {
public void show(){
System.out.println("demo1...show...");
}
}
package Demo2;
public class Demo2 {
public void show(){
System.out.println("Demo2...show...");
}
}
package Demo2;
public @interface Myanno {
int value();
String name() default"pofen";//不给name赋值默认pofen
Myanno2 anno2();
String[] str();
Person per();
// String show2();
// Person per();
// Myanno2 anno2();
// String[] str();
//public abstract String show();
}
package Demo2;
public @interface Myanno2 {
}
package Demo2;
import java.lang.annotation.*;
@Target(value ={ElementType.METHOD,ElementType.TYPE.FIELD})//表示该Myanno3只能作用于类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Myanno3 {
}
package Demo2;
public enum Person {//枚举
P1,P2,p3;
}
package Demo2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//描述需要执行的类名和方法名
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface pro {
String className();
String methodName();
}
package Demo2;
@pro(className = "Demo2",methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws Exception {
/*
前提:不能该表该类的任何代码,可以创建任意对象,可以执行任意方法
*/
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//2.获取上边的注解对象
pro an = reflectTestClass.getAnnotation(pro.class);
//其实就是在内存中生成流一个该·注解接口的子类实现对象
//调用注解对象定义的抽象方法获取返回值
String className = an.className();
String methodName = an.methodName();
System.out.println(className);
System.out.println(methodName);
}
}
package Demo2;
@Myanno( value = 12 ,per = Person.P1,anno2 = @Myanno2,str={"a","b"})
@Myanno3()
public class Worker {
@Myanno3
public String name = "aaa";
@Myanno3
public void show(){
}
- 小结
- 以后大多数时候会使用注解,而不是自定义注解
- 注解给谁用?1.编译器,2.给解析程序用
- 注解不是程序的一部分,可以理解为注解就是一个标签
package Demo3;
public class Caculator {
@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");
}
}
package Demo3;
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 {
}
package Demo3;
import javax.swing.*;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
public class TestCheck {
public static void main(String[] args) throws IOException {
//创建计算器对象
Caculator c = new Caculator();
//2.获取字节码文件对象
Class cls = c.getClass();
//3.获取所有方法
Method[] methods = cls.getMethods();
int number = 0;//出现异常次数
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for(Method method : methods) {
//4.判断方法上是否有Check注解
if (method.isAnnotationPresent(Check.class)) {
//5.有,执行
try {
method.invoke(c);
} catch (Exception e) {
//6.捕获异常
//记录到文件中
number++;
bw.write("xxx方法出现异常了");
bw.newLine();
bw.write("异常的名称:" + e.getCause().getCause());
bw.newLine();
bw.write("异常的原因:" + e.getCause().getMessage());
bw.newLine();
bw.write("------------");
}
}
}
bw.write("本次测试一个出现"+number+"次异常");
bw.flush();
bw.close();
}
}