笔记-JavaWeb学习之旅
junit单元测试
- 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值
- 白盒测试:需要些代码,关注程序具体的执行流程
junit使用: 白盒测试
步骤:
定义一个测试类(测试用例)
定义测试方法:可以独立运行
给方法加注解(@test)(需要加上注解才可以独立运行方法)
导入junit的依赖环境
-
判定结果:
红色:测试失败
绿色:测试成功
一般我们使用断言来处理结果asser.assertequals(期望的结果,实际结果);
补充:@before:
修饰的方法会在测试方法之前被自动执行
@after:
修饰的方法会在测试方法执行之后被执行
package cn.itcast.junit; //计算器类 public class calculator { public int add(int a,int b){ return a+b; } public int sub(int a ,int b){ return a-b; } }
package cn.itcast.test; //需要导入junit包,才可以独立运行方法 import cn.itcast.junit.calculator; import org.junit.after; import org.junit.assert; import org.junit.before; import org.junit.test; /** * @author: a * @date: 2019/5/30 10:33 * @version 1.0 * 测试add方法 */ public class calculatortest { /* * 初始化方法 * 用于资源申请,所有测试方法在执行之前都会先执行此方法 * */ @before public void init(){ system.out.println("init......"); } /* * 释放资源方法 * 在所有测试方法执行完毕后,都会执行该方法 * */ @after public void close(){ system.out.println("close..."); } @test public void testadd(){ //system.out.println("我被执行了"); //创建计算器对象 calculator c = new calculator(); //调用add方法 int result = c.add(1,2); system.out.println(result); //断言 //我期望的结果是2,真实结果不是,断言失败 //程序控制台出现红色 assert.assertequals(3,result); } } //init...... //3 //close...
反射:框架设计的灵魂
- 框架:半成品软件。可以在框架的基础上进行软件开发,简化代码
- 反射:将类的各个组成部分封装为其他对象,这就是反射机制(组成部分包括成员方法,成员变量,构造方法等)
- 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
获取class对象的方式:
- class.forname("全类名"):将字节码文件加载进内存,返回class对象
- 类名.class:通过类名的属性class获取
- 对象.getclass()
//class.forname("全类名") //多用于配置文件 class cls1 = class.forname("cn.itcast.domain.person"); //类名.class //多用于参数的传递 class cls2 = person.class; //对象.getclass() //多用于对象的获取字节码的方式 person p = new person(); class cls3 = p.getclass();
field:成员变量
常用方法
1.设置值 void set (object obj ,object value)
2.获取值 get (object obj)参数需要传递对象,
3.忽略访问权限修饰符的安全检查 setaccessible(true)
获取成员变量
package cn.itcast.reflect; //接下来要写的几个获取功能的类都与此类有关联 public class person { private string name; private int age; public string a; protected string b; string c; private string d; public person() { } public person(string name, int age) { this.name = name; this.age = age; } public string getname() { return name; } public int getage() { return age; } public void setname(string name) { this.name = name; } public void setage(int age) { this.age = age; } @override public string tostring() { return "person{" + "name='" + name + '\'' + ", age=" + age + ", a='" + a + '\'' + ", b='" + b + '\'' + ", c='" + c + '\'' + ", d='" + d + '\'' + '}'; } public void eat(){ system.out.println("eat...."); } public void eat(string food){ system.out.println("eat...."+food); } }
package cn.itcast.reflect; import java.lang.reflect.field; public class reflectdemo { public static void main(string[] args) throws exception{ //获取person的class对象 class personclass = person.class; //调用class对象的方法getfields获取成员变量,返回的是field[] 成员变量的数组 //获取所有的public 修饰的成员变量 field[] fields = personclass.getfields(); //对fields遍历,获取每一个public修饰的成员变量 for(field field :fields){ system.out.println(field); } //获取指定名称的public 修饰的成员变量 //field getfield(string name) field a =personclass.getfield("a"); //获取成员变量a的值,需要使用get(object obj)方法,需要传递对象参数 person p = new person(); object value = a.get(p); system.out.println(value);//null //设置成员变量a的值 a.set(p,"张三"); system.out.println(p); system.out.println("===================="); //获取所有的成员变量,不考虑修饰符 field[] declaredfields = personclass.getdeclaredfields(); for(field dec :declaredfields){ system.out.println(dec); } //获取指定名称的成员变量 //field getdeclaredfield(string name) field d =personclass.getdeclaredfield("d"); //忽略访问权限的修饰符的安全检查 d.setaccessible(true); //获取成员变量的值,需要传递对象参数 object value2 = d.get(p); system.out.println(value2); } }
constructor:构造方法
创建对象: t new instance(oject... initargs)参数是对象构造方法的参数类型
如果使用空参数构造方法创建对象,操作可以简化:class对象的newinstance方法
获取构造方法
package cn.itcast.reflect; import java.io.objectstreamclass; import java.lang.reflect.constructor; public class reflectdemo1 { public static void main(string[] args) throws exception{ //获取person的class对象 class personclass = person.class; //获取class对象的构造方fa constructor c =personclass.getconstructor(string.class,int.class); system.out.println(c); //构造方法用来创建对象的, //constructor 有个方法newinstance可以创建对象 object person = c.newinstance("张三",22); system.out.println(person); //使用空参数构造器创建对象 constructor c1 =personclass.getconstructor(); system.out.println(c1); object person1 = c1.newinstance(); system.out.println(person1); //可以通过class对象方法直接创建空参数的构造器 object o = personclass.newinstance(); system.out.println(o); } }
获取成员方法与类
method:方法对象
执行方法:object invoke(object obj,object...args) 需要传递真实的对象与参数列表
获取类名:
string getname()
package cn.itcast.reflect; import java.lang.reflect.method; public class reflectdemo2 { public static void main(string[] args) throws exception{ //获取person的class对象,返回的是一个class类 class personclass = person.class; //获取指定的public成员方法 //需要传递方法的名称,返回值是method类 method eat_method =personclass.getmethod("eat"); person p = new person(); eat_method.invoke(p);//eat.... //获取有参数的成员方法,需要传递方法名称 method eat_method2 =personclass.getmethod("eat",string.class); //获取到方法,就要执行方法 //执行方法,需要传递对象和参数 eat_method2.invoke(p,"饭"); //获取所有public 方法 method[] allmethod = personclass.getmethods(); for(method method : allmethod){ //获取方法的名称getname(); system.out.println(method.getname()); system.out.println(method); } //获取类名 string classname=personclass.getname(); system.out.println(classname);//cn.itcast.reflect.person } }
案例
需求:写一个框架,不能改变给类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意的方法
步骤:
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 在程序中加载读取配置文件
- 使用反射技术来加载类文件进内存
- 创建对象
- 执行方法
package cn.itcast.reflect; import java.io.inputstream; import java.lang.reflect.method; import java.util.properties; public class reflecttest { public static void main(string[] args) throws exception{ //加载配置文件 //创建properties对象 properties pro = new properties(); //获得class字节码文件 class c = reflecttest.class; //通过字节码文件c下的方法getclassloader 可以获得一个类加载器 classloader cl = c.getclassloader(); //可以通过classloader类下的方法“getresourceasstream(string name)”可以找到需要的配置文件获得一个字节输入流 //传递的参数为要加载的文件,获取字节输入流 inputstream is= cl.getresourceasstream("pro1.properties"); //properties 类的方法 “load(inputstream instream);”需要一个字节输入流的参数 //可以使用properties集合中的方法load,把硬盘中保存的文件,读取到集合中使用 pro.load(is);//配置文件加载完成 //获取配置文件中定义的数据 string classname = pro.getproperty("classname"); string methodname=pro.getproperty("methodname"); //加载该类进内存, class cls= class.forname(classname); //创建对象,可以通过class中的方法newinstance来获取 object obj= cls.newinstance(); //获取指定的成员方法 method method = cls.getmethod(methodname); //执行方法,需要传递对象obj method.invoke(obj); } } //似懂非懂……懂非懂…………非懂………………懂…………
注解
定义:注解(annotation),也叫元数据,一种代码级别的说明,他是jdk1.5及以后版本引入的一个特性,与类,接口枚举是在同一个层次,他可以声明在包,类,字段,方法,局部变量,方法参数等的前面,用来对这些元素进行说明,注释
作用分类:
- 编写文档:通过代码里标识符的注解生产文档
- 代码分析:通过代码里标识的注解对代码进行分析
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查
jdk中预定的一些注解
@override :检测被该注解标注的方法是否是继承自父类的
@deprecated: 该注解标注的内容,表示已过世
@suppresswarnings:压制警告
自定义注解
格式:
元注解:
public @interface 注解名称{}
本质:注解本质上就是一个接口,该接口默认继承annotation接口
属性:接口中可以定义成员方法
属性的返回值类型
1.基本数据类 2.string 3.枚举 4.注解 5.以上类型的数组
定义了属性,在使用时要给属性赋值
1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不就行属性的赋值
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
- 数组赋值时,值使用{}包裹,如果数组中只有一个值则{}省略
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
元注解:用于描述注解的注解
@target:描述注解能够作用的位置
elementtype取值:type:可以作用于类上; method:可以作用于方法上 field:可以作用于成员变量上
@retention: 描述注解能被保留的阶段
@retention(retentionpolicy,runtime):当前被描述的注解,会保留到class字节码文件中,并被jvm读取到
@documented:描述注解是否被抽取到api文档中
@inherited:描述注解是否被子类继承
package cn.itcast.reflect; public @interface myanno2 { }
package cn.itcast.reflect; //枚举类的定义 public enum person2 { p1,p2; }
package cn.itcast.reflect; public @interface myanno { //注解可以返回的类型 // 1.基本数据类 2.string 3.枚举 4.注解 5.以上类型的数组 int show1(); public abstract string show2() default "张三"; public abstract person2 per(); myanno2 anno2(); //string[] strs();*/ }
package cn.itcast.reflect; //string类型的返回值已经被default修饰了,可以不用对属性进行赋值 @myanno(show1=1,per=person2.p1,anno2=@myanno2) public class worker { }
注解案例练习
package cn.itcast.reflect; 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 cn.itcast.reflect; public class calculator { //加法 @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 cn.itcast.reflect; import java.io.bufferedwriter; import java.io.filewriter; import java.io.ioexception; import java.lang.reflect.method; /** * 简单的测试框架 * 当主方法执行后,会自动检测所有方法(加了check注解的方法) */ public class testcheck { public static void main(string[] args) throws ioexception { //创建计算器对象 calculator c = new calculator(); //获取字节码文件 class cls = c.getclass(); //获取所有方法 method[] methods = cls.getmethods(); int number =0;//出现异常的次数 bufferedwriter bw = new bufferedwriter(new filewriter("bug.txt")); for(method method : methods){ //判断方法上是否有check注解 if(method.isannotationpresent(check.class)){ //有,执行 try{ method.invoke(c); }catch (exception e){ //捕获异常 //记录到文件中 number++; bw.write("方法出异常了"); bw.newline(); bw.write("异常名称:"+e.getcause()); bw.newline(); bw.write("异常的原因"+e.getcause().getmessage()); bw.newline(); bw.write("--------------------"); bw.newline(); } bw.write("本次测试一共出现"+number+"次异常"); bw.flush(); } } } }
/* *本次测试一共出现0次异常本次测试一共出现0次异常方法出异常了 异常名称:java.lang.arithmeticexception: / by zero 异常的原因/ by zero -------------------- 本次测试一共出现1次异常本次测试一共出现1次异常 /
推荐阅读
-
iOS学习笔记-139.RunLoop07——Runloop处理流程
-
Python学习笔记之os模块使用总结
-
7.1(java学习笔记)InetAddress&InetScoketAddress
-
Python学习笔记(一)(基础入门之环境搭建)
-
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
-
python网络编程学习笔记(10):webpy框架
-
wxpython学习笔记(推荐查看)
-
Linux学习笔记(十四)磁盘管理(二):格式化、挂载以及Swap分区
-
JavaScript中的Number数字类型学习笔记
-
Python ORM框架SQLAlchemy学习笔记之关系映射实例