我是靠谱客的博主 搞怪香水,这篇文章主要介绍【Java进阶】Day11Junit 单元测试反射注解,现在分享给大家,希望可以做个参考。

Junit 单元测试

通过导入Junit模块可以使我们可以独立运行方法。
导入方法:在方法上方添加注解@Test然后Alt+回车跳出提示,选择将’JUnit4’添加到类路径中。
image.png
导入之后就可以直接执行该方法了,需要注意的是这个方法不能为static
image.png
如果正常运行下方会显示绿色,失败会显示红色。正常运行不代表结果会是我们想要的结果。在Junit测试中,使用断言(即断定结果是多少)的方法去判断运算是否正常。
下面我使用了Assert.assertEquals(期望值,运算结果,偏差)来判断程序输出是否是我想要的,这里我期望程序结果是0.3,但实际上是不精确的小数,就提示我运算不正确。
image.png
除了浮点数的比较,Junit还提供了其他类型的比较。
image.png

建议:

在使用Junit之前,我们需要创建一个测试类和测试方法。在命名方面有些建议,用于大型项目中告知是测试用例。

定义测试类(测试用例)

测试类名:被测试的类名 功能名+Test,CalculatorTest
包名:xxx.xxx.xx.test,cn.itcast.test

定义测试方法

方法名:test方法名,testAdd
返回值:void
参数列表:空参

生命周期

我们可以使用注解@Before@After来控制初始化方法和释放资源的方法。
image.png

  • @Before修饰的方法会在测试方法之前被自动执行
  • @After修饰的方法会在测试方法执行之后自动被执行

反射

框架设计的灵魂,如果需要写框架就需要深入学习反射。
反射:将类的各个组成部分封装为其他对象。让我们在程序运行过程中可以操作这些对象,并且经过封装后可以降低耦合,提高程序的扩展性。
字节码文件(.class),通过类加载器加载Class类对象,这个Class对象用于描述字节码文件。Class 是一个特殊的Java类,它可以保存类运行时的标识(类的一系列信息)。
image.png
image.png
image.png

操作成员变量

在测试之前创建了一个命名为Person的实体类,并定义了两个私有成员变量和一个公开成员变量。
image.png
image.png
获取类里面所有 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 * */

image.png
操作 public 修饰的成员变量。

复制代码
1
2
3
4
5
6
7
8
9
10
Class<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
12
Class<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实体类,在其中定义了三个构造方法,帮助我们初始化那三个变量。
image.png
除此之外还重写了toString方法。
image.png
image.png
获取所有 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) * */

image.png

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Class<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中针对agename都设置了setget方法。除此之外我再新增一个方法用来同时输出这两个变量。
image.png
image.png
获取类中所有权限为 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() */

image.png
使用 invoke 执行方法。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
Class<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
8
Class<Person> pc = Person.class; String name = pc.getName(); System.out.println(name); /* 输出: com.learn.obj.Person */

注解

大多数时候,我们使用注解,而不是自定义注解。
注解配合注解解析器来帮助我们完成一些事情,例如替代配置文件IO读写、在编译器处检查代码是否有异常、生成API文档等。注解并不是程序的一部分,可以理解为注解就是一个标签。

内置注解

  1. @SuppressWarnings压制警告

一般是给class上使用,且传递all参数。@SuppressWarnings("all")即是压制所有警告。

  1. @Override检测被该注解标注的方法是否是继承自父类重写的。
  2. @Deprecated被该注解标注的内容,表示已过时。

自定义注解

image.png
存在一个命名为EnumPerson的枚举。

复制代码
1
2
3
4
5
public enum EnumPerson { Poor, Rich }

存在一个没有任何意义的注解public @interface MyAnno2 { }
演示注解可以拥有的属性值数据类型。

复制代码
1
2
3
4
5
6
7
public @interface MyAnno { int[] count() default {1,3}; String[] name() default {"我","你"}; EnumPerson value() default EnumPerson.Poor; Class<MyAnno2> mya() default MyAnno2.class; }

image.png
元注解我们一般只使用两个,分别是@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"); } } }
  1. 创建了一个测试类,通过类名.class的方式获取了Login的Class对象。
  2. 通过isAnnotationPresent方法判断是否被标注了@MyAnno
  3. 通过getAnnotation获得接口MyAnno的实现类,类似于下面的代码
复制代码
1
2
3
4
5
public class MyAnnoImpl implements MyAnno{ public String username(){return "admin"}; public String password(){return "123456"}; }
  1. 同调用usernamepasswordlogin方法传递形参。
复制代码
1
2
3
4
5
6
7
8
9
10
11
public 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()); } } }

image.png
image.png

最后

以上就是搞怪香水最近收集整理的关于【Java进阶】Day11Junit 单元测试反射注解的全部内容,更多相关【Java进阶】Day11Junit内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(115)

评论列表共有 0 条评论

立即
投稿
返回
顶部