1. Junit 单元测试
1. 测试简介2. JUnit 单元测试
1. JUnit 简介2. JUnit 配置
1. IDEA 中配置 JUnit2. Eclipse 中配置 JUnit 4. JUnit 的使用
测试步骤示例 5. 异常处理6. @Before 和 @After 2. 反射:框架设计的灵魂
1. 相关概念2. 成员变量,构造方法,方法对象3. 获取 Class 对象的方式
示例 3. Class 对象的功能介绍
1. 获取成员变量2. 获取构造方法3. 获取成员方法4. 获取全类名5. 记忆方法 3. 注解
1. 相关概念2. 注解的作用3. 注解的分类
1. 预定义注解2. 自定义注解3. 元注解 4. 解析注解
示例
测试一般有两种,根据测试代码是否可见分为以下两种测试。
黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
黑盒测试就如上图一样,像一个黑色的盒子,测试人员在测试时无需关注代码内部的实现逻辑,只需要向黑盒中输入一个值,观察输出的值是否符合预期输出结果的情况。
白盒测试:需要写代码。根据程序的具体执行流程。
白盒测试则相反,没有像黑盒测试一样对代码进行隐藏,测试人员会利用程序内部的逻辑结构及有关信息,通过在不同点检查程序状态,检验程序中的每条通路是否都能按预定要求进行正确工作。
在我们写代码的时候,经常会需要测试代码的内部逻辑,这时我们可以使用 JUnit 来进行白盒测试。JUnit 是一个 Java 编程语言的单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。 2. JUnit 配置 1. IDEA 中配置 JUnit
IDEA 中默认安装了 JUnit 插件,在 IDEA 的 File(文件) --> Setting(设置) --> Plugins(插件) 中搜索 JUnit 即可看到,如果自己的 IDEA没有,可以搜索 JUnit 并安装。
Eclipse 中配置 JUnit 就会稍微麻烦一点了。
① 找到自己的项目,右击点击项目文件 --> 点击 Build Path --> 点击 Add Libraries
② 点击 JUnit
③ 选择自己需要的 JUnit 版本,并点击 Finish 即可。
在学习 JUnit 之前,我们测试的时候,一般都是定义一个测试类来对我们的程序进行测试。
Demo类
public class Demo {
public void printHelloWorld(){
System.out.println("Hello World");
}
public int add(int a, int b){
return a+b;
}
public int sub(int a, int b){
return a-b;
}
}
DemoTest 类
public class DemoTest {
public static void main(String[] args) {
// 创建对象
Demo demo = new Demo();
// 调用
//demo.printHelloWorld();
int num = demo.sub(1,2);
System.out.println(num);
}
}
但是当我们需要测试多个方法的时候,我们就需要把测试类中调用的方法注释掉,才能测试下一个方法,这样测试起来会很麻烦,于是下面便介绍 JUnit测试。
测试步骤
① 定义一个测试类
建议:
测试类名:被测试的类名Test包名:xxx.xxx.xxx.test
② 定义一个测试方法
建议:
方法名:test测试的方法名返回值:void参数列表:空参
③ 给方法加 @Test
④ 导入 JUnit 依赖环境
点击报错位置的红色灯,再点击 Add 'JUnit' to classpath 即可。
import org.junit.Test;
public class DemoTest {
@Test
public void testPrintHelloWorld(){
// 创建对象
Demo demo = new Demo();
// 调用方法
demo.printHelloWorld();
}
@Test
public void testAdd(){
// 创建对象
Demo demo = new Demo();
// 调用方法
System.out.println(demo.add(1,3));
}
@Test
public void testSub(){
// 创建对象
Demo demo = new Demo();
// 调用方法
System.out.println(demo.sub(1,3));
}
}
测试结果正确的方法就会出现绿色对号,出现异常的方法就会出现红色灯泡。
一般我们使用断言(Assert)来测试异常的结果。Assert可以帮助我们假定预期输出结果与真实输出结果是否相同。
// 格式 Assert.assertEquals(expected,actual);
这里我们假定输出结果为3。
@Test
public void testAdd(){
// 创建对象
Demo demo = new Demo();
// 调用方法
int num = demo.add(1,3);
//System.out.println(num);
// 断言处理
Assert.assertEquals(3,num); //假定输出结果为3
}
可以看到,当真实输出结果和预期输出结果不同时,输出预期值和真实值,并报错。此时我们就需要对我们的代码进行处理
6. @Before 和 @After@Before:初始化方法,修饰的方法会在测试方法之前被自动执行
@Before
public void init(){
System.out.println("init...");
};
@After:释放资源方法,修饰的方法会在测试方法执行之后自动被执行
@After
public void close(){
System.out.println("close...");
}
结果:
更多
1. 相关概念
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码。
反射:将类的各个组成部分封装为其他对象,这就是反射机制
通过反射,我们可以更容易的对 类对象阶段更好地操作成员变量,构造方法,成员方法等。
反射的好处:
① 可以在程序运行过程中,操作这些对象。② 可以解耦,提高程序的可扩展性。 2. 成员变量,构造方法,方法对象
① Field:成员变量
- 设置值
void set(Object obj, Object value)
- 获取值
get(Object obj)
- 忽略访问权限修饰符的安全检查
setAccessible(true) //暴力反射
② Constructor:构造方法
- 创建对象
T newInstance(Object... initargs)
③ Method:方法对象
- 执行方法
Object invoke(Object obj, Object... args)
- 获取方法名称
String getName:获取方法名3. 获取 Class 对象的方式
① Class.forName("全类名"):将字节码文件加载进内存,返回Class对象。多用于配置文件,将类名定义在配置文件中。读取文件,加载类② 类名.class:通过类名的属性class获取。多用于参数的传递③ 对象.getClass():getClass()方法在Object类中定义。多用于对象的获取字节码的方式
同一个字节码文件(.class)在一次程序运行中,只会被加载一次,不论通过哪种方式获取的Class对象都是同一个。
示例public class Demo {
public int a;
public char b;
public Demo(){ }
public void function() {}
}
class ReflectDemo{
public static void main(String[] args) {
// 获取Class对象
Class cls = Demo.class;
System.out.println(cls);
}
}
更多
3. Class 对象的功能介绍 1. 获取成员变量| 方法名 | 说明 |
|---|---|
| Field[] getFields() | 获取所有public修饰的成员变量,包括从父类继承的成员变量 |
| Field getField(String name) | 获取指定名称的 public修饰的成员变量,包括从父类继承的成员变量 |
| Field[] getDeclaredFields() | 获取所有的成员变量,不考虑修饰符,不包括从父类继承的成员变量 |
| Field getDeclaredField(String name) | 获取指定名称的成员变量,不考虑修饰符,不包括从父类继承的成员变量 |
| 方法名 | 说明 |
|---|---|
| Constructor>[] getConstructors() | 返回所有的构造方法,考虑修饰符 |
| Constructor | 返回指定参数类型的构造方法,考虑修饰符 |
| Constructor | 返回指定参数类型的构造方法,不考虑修饰符 |
| Constructor>[] getDeclaredConstructors() | 返回所有的构造方法,不考虑修饰符 |
| 方法名 | 说明 |
|---|---|
| Method[] getMethods() | 获取所有的成员方法,考虑修饰符 |
| Method getMethod(String name, 类>... parameterTypes) | 获取指定的成员方法,考虑修饰符 |
| Method[] getDeclaredMethods() | 获取所有的成员方法,不考虑修饰符 |
| Method getDeclaredMethod(String name, 类>... parameterTypes) | 获取的指定的成员方法,不考虑修饰符 |
| 方法名 | 说明 |
|---|---|
| String getName() | 获取类的全类名 |
在方法名末尾有s的是返回一个数组,没有s的是返回单个方法或变量。在方法名中加 Declared 的是返回所有的方法或变量,不加 Declared 的只返回 public 访问权限的方法或变量有参数的获取方法都是在方法名中没有在结尾处加s的,返回的是指定参数类型的方法和变量 3. 注解 1. 相关概念
注解和注释差不多,只不过所面向的对象不一样。
注解:说明程序,给计算机看的
注释:描述程序,给人看的
注解定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
2. 注解的作用注解一般有以下三种作用:
① 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】② 代码分析:通过代码里标识的注解对代码进行分析【使用反射】③ 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】 3. 注解的分类
注解一般分为预定义注解和自定义注解。
1. 预定义注解预定义注解也就是 JDK 中事先定义好的一些注解。常见的一些注解如下:
@Override :检测被该注解标注的方法是否是继承自父类(接口)的。
class Demo_father {
public void show(){
System.out.println("1");
}
}
public class Demo extends Demo_father{
public int a;
public char b;
public Demo(){ }
public void function() {}
@Override
public void show() { //继承父类的方法
super.show();
}
}
@Deprecated:该注解标注的内容,表示已过时,如果使用该方法,会报编译警告。
class Demo_father {
public void show(){
System.out.println("1");
}
}
public class Demo extends Demo_father{
public int a;
public char b;
public Demo(){ }
public void function() {}
@Override
public void show() {
super.show();
}
@Deprecated
public void print(){
System.out.println("Hello World");
}
public void test(){
print();
}
}
被 @Deprecated 注解的方法在调用时被画横线,并不意味着不能用,但不推荐使用。
@SuppressWarnings:压制警告,一般传递参数all @SuppressWarnings("all")。
使用前,出现警告
使用后,警告消失
@Override 代码
① 格式:
元注解
public @interface 注解名称{
属性列表;
}
示例:MyAnnotation就是一个注解,并能使用,没有报错。
② 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnnotation extends java.lang.annotation.Annotation {}
③ 属性:接口中的抽象方法
两个要求:
(1) 属性的返回值类型有下列取值
基本数据类型String枚举注解以上类型的数组 (2) 定义了属性,在使用时需要给属性赋值
- 如果定义属性时,使用 default 关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。如果只有一个属性需要赋值,并且属性的名称是 value ,则 value 可以省略,直接定义值即可。数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
元注解用来描述注解的注解,主要有以下几个:
① @Target:描述注解能够作用的位置
ElementType取值:
TYPE:可以作用于类上METHOD:可以作用于方法上FIELD:可以作用于成员变量上
② @Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
③ @documented:描述注解是否被抽取到api文档中
④ @Inherited:描述注解是否被子类继承
4. 解析注解① 获取注解定义位置的对象(Class,Method,Field)
② 获取指定的注解
③ 调用注解中的抽象方法获取配置的属性值
import java.lang.annotation.*;
@documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String show();
}
@MyAnnotation(show = "Hello World")
class Demo_father {
}
public class Demo {
public static void main(String[] args) {
// 获取字节码文件
Class demo_fatherClass = Demo_father.class;
// 获取注解对象
MyAnnotation myAnnotation = demo_fatherClass.getAnnotation(MyAnnotation.class);
// 调用注解中的抽象方法,获取返回值
System.out.println(myAnnotation.show());
}
}
结果:



