一、单元测试
就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。
1. 咱们之前是如何进行单元测试的?有啥问题?
- 只能在main方法编写测试代码,去调用其他方法进行测试。
- 无法实现自动化测试,一个方法测试失败,可能影响其他方法的测试。
- 无法得到测试的报告,需要程序员自己去观察测试是否成功。
2. Junit单元测试框架
- 可以用来对方法进行测试,它是第三方公司开源出来的(很多开发工具已经集成了Junit框架,比如IDEA)
2.1 优点
- 可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立.
- 不需要程序员去分析测试的结果,会自动生成测试报告出来。
2.2 快速入门
需求:某个系统,有多个业务方法,请使用Junit单元测试框架,编写测试代码,完成对这些方法的正确性测试。
具体步骤
- 将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了)
- 为需要测试的业务类,定义对应的测试类,并为每个业务方法,编写对应的测试方法(必须:公共、无参、无返回值)
- 测试方法上必须声明@Test注解,然后在测试方法中,编写代码调用被测试的业务方法进行测试;
- 开始测试:选中测试方法,右键选择“JUnit运行”,如果测试通过则是绿色;如果测试失败,则是红色
可以右键模块,run all test自动化一键测试,可以点击测试类的运行运行该类的所有自动化测试。
package com.jingwei;
import org.junit.Assert;
import org.junit.Test;
public class StringUtilTest {
@Test
public void testPrintNumber(){
StringUtil.printNumber("admin");
StringUtil.printNumber(null);
}
@Test
public void testGetMaxIndex(){
int maxIndex = StringUtil.getMaxIndex(null);
System.out.println(maxIndex);
int maxIndex1 = StringUtil.getMaxIndex("admin");
System.out.println(maxIndex1);
//断言机制:程序员可以通过预测业务方法的结果
Assert.assertEquals(4,maxIndex1);
}
}
package com.jingwei;
public class StringUtil {
public static void printNumber(String name) {
if(name==null){
System.out.println("名字长度是:" +0);
return;
}
System.out.println("名字长度是:" + name.length());
}
//求字符串的最大索引
public static int getMaxIndex(String data) {
if (data == null) {
return -1;
}
return data.length()-1;
}
}
2.3 常用注解
package com.jingwei;
import org.junit.*;
import java.net.Socket;
public class StringUtilTest {
private Socket socket;
private static Socket socket1;
@Before
public void setUp() throws Exception {
System.out.println("--->Setup Before 测试配置文件执行了---------");
socket = new Socket("127.0.0.1", 8888);
}
@After
public void setUp1() throws Exception {
System.out.println("--->Setup After 测试配置文件执行了---------");
socket.close();
}
@BeforeClass
public static void setUp2() throws Exception {
System.out.println("--->Setup BeforeClass 测试配置文件执行了---------");
socket1=new Socket("127.0.0.1", 8888);
}
@AfterClass
public static void setUp3() throws Exception {
System.out.println("--->Setup AfterClass 测试配置文件执行了---------");
socket1.close();
}
@Test
public void testPrintNumber(){
StringUtil.printNumber("admin");
StringUtil.printNumber(null);
}
@Test
public void testGetMaxIndex(){
int maxIndex = StringUtil.getMaxIndex(null);
System.out.println(maxIndex);
int maxIndex1 = StringUtil.getMaxIndex("admin");
System.out.println(maxIndex1);
//断言机制:程序员可以通过预测业务方法的结果
Assert.assertEquals(4,maxIndex1);
}
}
二、反射
2.1 反射(Reflection)
反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。
2.2 反射学什么?
学习获取类的信息、操作它们
1、反射第一步:加载类,获取类的字节码:Class对象
2、获取类的构造器:Constructor对象
3、获取类的成员变量:Field对象
4、获取类的成员方法:Method对象
全部认识完后,再看反射的应用场景
package com.reflect;
public class ReflectTest1 {
public static void main(String[] args) throws ClassNotFoundException {
Class studentClass = Student.class;
System.out.println(studentClass.getName());
System.out.println(studentClass.getSimpleName());
Class aClass = Class.forName("com.reflect.Student");
System.out.println(aClass.getName());
System.out.println(studentClass == aClass);
Class tom = new Student("Tom",11).getClass();
System.out.println(tom.getName());
System.out.println(tom==studentClass);
}
}
class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
2.3 获取类的构造器
package com.reflect;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class ReflectTest2 {
@Test
public void testGetConstructors() {
//1. 反射第一步:必须先得到这个类的class对象
Class<Student> studentClass = Student.class;
//2. 获取类的全部构造器
// Constructor[] constructors = studentClass.getConstructors();
Constructor[] constructors = studentClass.getDeclaredConstructors();
//3. 遍历数组中的每个构造器对象
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "--->"
+ constructor.getParameterCount());
}
}
@Test
public void testGetConstructor() throws NoSuchMethodException {
Class<Student> studentClass = Student.class;
// Constructor<Student> constructor = studentClass.getConstructor();
Constructor constructor = studentClass.getDeclaredConstructor();
System.out.println(constructor.getName() + "--->"
+ constructor.getParameterCount());
Constructor constructor1 = studentClass.getDeclaredConstructor(String.class,int.class);
System.out.println(constructor1.getName() + "--->"
+ constructor1.getParameterCount());
}
}
获取类构造器的作用:依然是初始化一个对象返回
package com.reflect;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectTest2 {
@Test
public void testGetConstructors() {
//1. 反射第一步:必须先得到这个类的class对象
Class<Student> studentClass = Student.class;
//2. 获取类的全部构造器
// Constructor[] constructors = studentClass.getConstructors();
Constructor[] constructors = studentClass.getDeclaredConstructors();
//3. 遍历数组中的每个构造器对象
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "--->"
+ constructor.getParameterCount());
}
}
@Test
public void testGetConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Student> studentClass = Student.class;
// Constructor<Student> constructor = studentClass.getConstructor();
Constructor constructor = studentClass.getDeclaredConstructor();
System.out.println(constructor.getName() + "--->"
+ constructor.getParameterCount());
constructor.setAccessible(true);//禁止检查访问权限,可以访问私有构造器,破坏封装性能
Student o = (Student) constructor.newInstance();
System.out.println(o);
Constructor constructor1 = studentClass.getDeclaredConstructor(String.class, int.class);
System.out.println(constructor1.getName() + "--->"
+ constructor1.getParameterCount());
Student o1 = (Student) constructor1.newInstance("叮当猫", 3);
System.out.println(o1);
}
}
2.3 获取类的成员变量
@Test
public void testGetField() throws NoSuchFieldException, IllegalAccessException {
//1. 反射第一步:必须是先得到类的Class对象
Class<Student> studentClass = Student.class;
//2. 获取类的全部成员变量。
Field[] fields = studentClass.getDeclaredFields();
//3. 遍历这个成员变量数组
for (Field field : fields) {
System.out.println(field.getName() + "--->"+field.getType());
}
//4. 定位某个成员变量
Field declaredField = studentClass.getDeclaredField("name");
System.out.println(declaredField.getName()+"--->"+declaredField.getType());
Field age = studentClass.getDeclaredField("age");
System.out.println(age.getName()+"--->"+age.getType());
//赋值
Student student = new Student();
declaredField.setAccessible(true);
declaredField.set(student,"加菲猫");
System.out.println(student);
//取值
String rs = (String) declaredField.get(student);
System.out.println(rs);
}
2.4 获取类的成员方法
@Test
public void testGetMethod() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Student> studentClass = Student.class;
Method[] methods = studentClass.getDeclaredMethods();
System.out.println("所有成员方法如下:");
for (Method method : methods) {
System.out.println(method.getName() + "--->"+method.getParameterCount()
+"--->"+method.getReturnType());
}
System.out.println("---------");
Method declaredMethod = studentClass.getDeclaredMethod("setName", String.class);
System.out.println(declaredMethod.getName()+"--->"+declaredMethod.getParameterCount()
+"--->"+declaredMethod.getReturnType());
System.out.println("---------");
Method declaredMethod1 = studentClass.getDeclaredMethod("getName");
System.out.println(declaredMethod.getName()+"--->"+declaredMethod.getParameterCount()
+"--->"+declaredMethod.getReturnType());
Student student = new Student("Tom", 12);
String invoke = (String) declaredMethod1.invoke(student);
System.out.println(invoke);
Object invoke1 = declaredMethod.invoke(student, "Mike");
System.out.println(invoke1);
System.out.println(student.getName());
}
2.5 作用、应用场景
反射的作用?
- 基本作用:可以得到一个类的全部成分然后操作。
- 可以破坏封装性。
- 最重要的用途是:适合做lava的框架,基本上,主流的框架都会基于反射设计出一些通用的功能,
@Test
public void saveInfo() throws IOException, IllegalAccessException {
People tom = new People("Tom", 12);
Teacher mike = new Teacher("Mike", 21, 22, "123456789");
//需求:把任意对象的字段名和其对应的值等信息,保存到文件中去
ObjectFrame.saveInfo(tom);
ObjectFrame.saveInfo(mike);
}
package com.reflect;
import java.io.*;
import java.lang.reflect.Field;
public class ObjectFrame {
//需求:把任意对象的字段名和其对应的值等信息,保存到文件中去
public static void saveInfo(Object o) throws IllegalAccessException, IOException {
PrintStream printStream = new PrintStream(new FileOutputStream("src/com/reflect/info.txt", true));
Class<?> aClass = o.getClass();
String simpleName = aClass.getSimpleName();
printStream.println("-------------------------------"+simpleName+"--------------------------------");
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
String value = field.get(o)+"";
System.out.println(fieldName + ":" + value);
printStream.println(fieldName + "=" + value);
}
}
}
三、注解
3.1 自定义注解
注解(Annotation)
- 就是java代码里的特殊标记,比如:@Override、@Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序。
- 注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处。
package com.test;
/**
* 自定义注解
*/
public @interface TestAno {
String aaa();
boolean bbb() default true;
String[] ccc();
}
@interface TestAno2{
String value();//特殊属性
int age() default 23;
}
@TestAno(aaa = "牛魔王", bbb = true, ccc = {"abc", "cba", "ccc"})
@TestAno2("string")
class AnoTest1 {
@TestAno(aaa = "123", bbb = false, ccc = {"ads", "sda"})
public void test() {
}
}
- 注解本质是一个接口,Java中所有注解都是继承了Annotation接口的,
- @注解(…):其实就是一个实现类对象,实现了该注解以及Annotation接口。
3.2 元注解
指的是:修饰注解的注解
3.2 注解的解析
什么是注解的解析?
就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来。
如何解析注解?
- 指导思想:要解析谁上面的注解,就应该先拿到谁。
- 比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解。
- 比如要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解。
- Class、Method、Field,Constructor、都实现了AnnotatedElement接口,它们都拥有解析注解的能力。
package com.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
public class AnoTest3 {
public static void main(String[] args) throws NoSuchMethodException {
//1. 先得到class对象
Class<Demo> demoClass = Demo.class;
Method test1 = demoClass.getDeclaredMethod("test1");
//2. 解析类上的注解
boolean annotationPresent = demoClass.isAnnotationPresent(MyTest4.class);
System.out.println(annotationPresent);
if(annotationPresent){
MyTest4 declaredAnnotation = (MyTest4) demoClass.getDeclaredAnnotation(MyTest4.class);
System.out.println(declaredAnnotation.value());
System.out.println(declaredAnnotation.aaa());
System.out.println(declaredAnnotation.bbb());
}
}
}
package com.test;
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.TYPE,ElementType.METHOD})
public @interface MyTest4 {
String value();
double aaa() default 100;
String bbb();
}
package com.test;
@MyTest4(value = "蜘蛛精",aaa = 100,bbb = "孙吴炯")
public class Demo {
@MyTest4(value = "蜘蛛精",aaa = 100,bbb = "孙吴炯")
public void test1(){}
}
3.3 应用场景
package com.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AnnotationTest {
public void test1(){
System.out.println("test1");
}
@MyTest
public void test2(){
System.out.println("test2");
}
public void test3(){
System.out.println("test3");
}
@MyTest
public void test4(){
System.out.println("test4");
}
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
AnnotationTest annotationTest = new AnnotationTest();
//启动程序!
//1. 得到class对象
Class<AnnotationTest> annotationTestClass = AnnotationTest.class;
//2. 提取这类中的全部成员方法
Method[] declaredMethods = annotationTestClass.getDeclaredMethods();
//3. 遍历这个数组中的每个方法,看方法上是否存在@MyTest注解,存在触发该方法
for (Method declaredMethod : declaredMethods) {
// 说明当前方法上是存在@MyTest,触发当前方法执行
if(declaredMethod.isAnnotationPresent(MyTest.class)){
declaredMethod.invoke(annotationTest);
}
}
}
}
四、动态代理
4.1 代理
程序为什么需要代理?代理长什么样?
- 对象如果嫌身上干的事太多的话,可以通过代理来转移部分职责。
- 对象有什么方法想被代理,代理
就一定要有对应的方法
package com.reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static Star createProxy(BigStar bigStar) {
Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{Star.class},
new InvocationHandler() {
@Override//回调方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("sing")) {
System.out.println("唱歌收钱20w");
} else if (method.getName().equals("dance")) {
System.out.println("dance");
}
return method.invoke(bigStar, args);
}
});
return star;
}
}
class Test{
public static void main(String[] args) {
BigStar ycy = new BigStar("杨超越");
Star proxy = ProxyUtil.createProxy(ycy);
proxy.sing("好日子");
proxy.dance("跳舞");
}
}
package com.reflect;
public interface Star {
void sing(String name);
void dance(String name);
}
package com.reflect;
public class BigStar implements Star {
private String name;
public BigStar(String name) {
this.name = name;
}
public void sing(String name) {
System.out.println(this.name + " " + name);
}
public void dance(String name) {
System.out.println(this.name + " dance:" + name);
}
}