Junit 单元测试
通过导入Junit模块可以使我们可以独立运行方法。
导入方法:在方法上方添加注解@Test
然后Alt+回车
跳出提示,选择将’JUnit4’添加到类路径中。
导入之后就可以直接执行该方法了,需要注意的是这个方法不能为static
如果正常运行下方会显示绿色,失败会显示红色。正常运行不代表结果会是我们想要的结果。在Junit测试中,使用断言(即断定结果是多少)的方法去判断运算是否正常。
下面我使用了Assert.assertEquals(期望值,运算结果,偏差)
来判断程序输出是否是我想要的,这里我期望程序结果是0.3,但实际上是不精确的小数,就提示我运算不正确。
除了浮点数的比较,Junit还提供了其他类型的比较。
建议:
在使用Junit之前,我们需要创建一个测试类和测试方法。在命名方面有些建议,用于大型项目中告知是测试用例。
定义测试类(测试用例)
测试类名:被测试的类名 功能名+Test,CalculatorTest
包名:xxx.xxx.xx.test,cn.itcast.test
定义测试方法
方法名:test方法名,testAdd
返回值:void
参数列表:空参
生命周期
我们可以使用注解@Before
和@After
来控制初始化方法和释放资源的方法。
@Before
修饰的方法会在测试方法之前被自动执行@After
修饰的方法会在测试方法执行之后自动被执行
反射
框架设计的灵魂,如果需要写框架就需要深入学习反射。
反射:将类的各个组成部分封装为其他对象。让我们在程序运行过程中可以操作这些对象,并且经过封装后可以降低耦合,提高程序的扩展性。
字节码文件(.class),通过类加载器加载Class类对象,这个Class对象用于描述字节码文件。Class 是一个特殊的Java类,它可以保存类运行时的标识(类的一系列信息)。
操作成员变量
在测试之前创建了一个命名为Person
的实体类,并定义了两个私有成员变量和一个公开成员变量。
获取类里面所有 public 修饰的变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// getFields 方法 Class<Person> pc = Person.class; Field[] pcField = pc.getFields(); for (Field f : pcField){ System.out.println(f); } // getField 方法 Field sex = pc.getField("sex"); System.out.println(sex); /* * 输出: * public int com.learn.obj.Person.sex * public int com.learn.obj.Person.sex * */
获取类所有变量,无视权限修饰符。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// getDeclaredFields 方法 Class<Person> pc = Person.class; Field[] pcField = pc.getDeclaredFields(); for (Field f : pcField){ System.out.println(f); } // getDeclaredField 方法 Field sex = pc.getDeclaredField("sex"); System.out.println(sex); /* * 输出: * private int com.learn.obj.Person.age * private java.lang.String com.learn.obj.Person.name * public int com.learn.obj.Person.sex * public int com.learn.obj.Person.sex * */
操作 public 修饰的成员变量。
1
2
3
4
5
6
7
8
9
10Class<Person> pc = Person.class; Field publicValueSex = pc.getField("sex"); Person p = new Person(); publicValueSex.set(p, 1); Object po = publicValueSex.get(p); System.out.println(po); /* * 输出:1 * */
无视权限修饰符操作成员变量。
1
2
3
4
5
6
7
8
9
10
11
12Class<Person> pc = Person.class; Field privateValueAge = pc.getDeclaredField("age"); // 设置访问权限为 True privateValueAge.setAccessible(true); Person p = new Person(); privateValueAge.set(p, 23); Object po = privateValueAge.get(p); System.out.println(po); /* * 输出:23 * */
操作构造方法
为了方便测试还是使用Person
实体类,在其中定义了三个构造方法,帮助我们初始化那三个变量。
除此之外还重写了toString
方法。
获取所有 public 修饰的构造方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// getConstructors 方法 Class<Person> pc = Person.class; Constructor[] pcConstructors = pc.getConstructors(); for (Constructor c : pcConstructors){ System.out.println(c); } // getConstructor 方法 Constructor<Person> pc2 = pc.getConstructor(int.class, String.class); System.out.println(pc2); /* * 输出: * public com.learn.obj.Person(int,java.lang.String,int) * public com.learn.obj.Person(int,java.lang.String) * public com.learn.obj.Person() * public com.learn.obj.Person(int,java.lang.String) * */
1
2
3
4
5
6
7
8
9
10
11
12
13
14Class<Person> pc = Person.class; Constructor pConstructor = pc.getConstructor(); Object po = pConstructor.newInstance(); System.out.println(po); // 简化操作已弃用 Person person = pc.newInstance(); System.out.println(person); /* * 输出: * Person{age=0, name='null'} * Person{age=0, name='null'} * */
操作成员方法
实体类Person
中针对age
和name
都设置了set
和get
方法。除此之外我再新增一个方法用来同时输出这两个变量。
获取类中所有权限为 public 的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// getMethods 方法 Class<Person> pc = Person.class; Method[] pcMethods = pc.getMethods(); for (Method m : pcMethods){ // 通过 getName 获取方法名称 System.out.println(m.getName()); } // getMethod 方法 Method sayHello = pc.getMethod("sayHello"); System.out.println(sayHello); /* 输出: getName toString setName sayHello setAge getAge equals hashCode getClass notify notifyAll wait wait wait public void com.learn.obj.Person.sayHello() */
使用 invoke 执行方法。
1
2
3
4
5
6
7
8
9
10
11
12
13Class<Person> pc = Person.class; Method sayHello = pc.getMethod("sayHello"); Person p = new Person(24, "大牛"); sayHello.invoke(p); // 获取重载方法 Method sayHello2 = pc.getMethod("sayHello", String.class); sayHello2.invoke(p, "数学"); /* 输出: 你好,我是大牛,我今年24岁了。 你好,我是大牛,我今年24岁了,还在学习数学 */
获取类名
可以使用getName
方法获取类的全称(包名+类名)。
1
2
3
4
5
6
7
8Class<Person> pc = Person.class; String name = pc.getName(); System.out.println(name); /* 输出: com.learn.obj.Person */
注解
大多数时候,我们使用注解,而不是自定义注解。
注解配合注解解析器来帮助我们完成一些事情,例如替代配置文件IO读写、在编译器处检查代码是否有异常、生成API文档等。注解并不是程序的一部分,可以理解为注解就是一个标签。
内置注解
@SuppressWarnings
压制警告
一般是给class上使用,且传递all参数。@SuppressWarnings("all")
即是压制所有警告。
@Override
检测被该注解标注的方法是否是继承自父类重写的。@Deprecated
被该注解标注的内容,表示已过时。
自定义注解
存在一个命名为EnumPerson
的枚举。
1
2
3
4
5public enum EnumPerson { Poor, Rich }
存在一个没有任何意义的注解public @interface MyAnno2 { }
演示注解可以拥有的属性值数据类型。
1
2
3
4
5
6
7public @interface MyAnno { int[] count() default {1,3}; String[] name() default {"我","你"}; EnumPerson value() default EnumPerson.Poor; Class<MyAnno2> mya() default MyAnno2.class; }
元注解我们一般只使用两个,分别是@Target
和@Retention
1
2
3
4
5
6
7
8
9@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno { int[] count() default {1,3}; String[] name() default {"我","你"}; EnumPerson value() default EnumPerson.Poor; Class<MyAnno2> mya() default MyAnno2.class; }
解析注解
在程序中使用(解析)注解,主要目的是获取注解中定义的属性值。
下面演示一个代替配置文件的作用案例。我们将编写一个登录功能,我希望有正确用户名和密码的默认值。下方定义了一个MyAnno
注解,其中有两个属性,且只能标注于类。
1
2
3
4
5
6
7@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnno { String username() default "admin"; String password() default "123456"; }
编写登录功能,其中输入的用户名和密码从Scanner
进来,而默认正确的用户名和密码从形参中获得。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@MyAnno public class Login { public static void login(String defaultUser,String defaultPass) { Scanner sc = new Scanner(System.in); System.out.println("请输入你的用户名:"); String user = sc.nextLine(); System.out.println("请输入你的密码:"); String pass = sc.nextLine(); if (user.equals(defaultUser) && pass.equals(defaultPass)){ System.out.println("pass"); } else { System.out.println("error"); } } }
- 创建了一个测试类,通过
类名.class
的方式获取了Login
的Class对象。 - 通过
isAnnotationPresent
方法判断是否被标注了@MyAnno
。 - 通过
getAnnotation
获得接口MyAnno
的实现类,类似于下面的代码
1
2
3
4
5public class MyAnnoImpl implements MyAnno{ public String username(){return "admin"}; public String password(){return "123456"}; }
- 同调用
username
和password
给login
方法传递形参。
1
2
3
4
5
6
7
8
9
10
11public class LoginTest { public static void main(String[] args) { Class<Login> loginClass = Login.class; if (loginClass.isAnnotationPresent(MyAnno.class)){ MyAnno myAnno = loginClass.getAnnotation(MyAnno.class); Login.login(myAnno.username(), myAnno.password()); } } }
最后
以上就是搞怪香水最近收集整理的关于【Java进阶】Day11Junit 单元测试反射注解的全部内容,更多相关【Java进阶】Day11Junit内容请搜索靠谱客的其他文章。
发表评论 取消回复